Compare commits

..

75 Commits

Author SHA1 Message Date
Elliot DeNolf
2c4da93b28 chore(release): v3.0.0-beta.52 [skip ci] 2024-06-18 18:18:10 -04:00
James Mikrut
cf50eabbab fix(payload): generated types issues (#6840)
## Description

Fixes types broken by recent prebundling / new exports consolidation
2024-06-18 18:14:08 -04:00
Alessio Gravili
bf374a23ab feat(payload, richtext-lexical): runtime dependency checks (#6838) 2024-06-18 21:11:07 +00:00
Alessio Gravili
223d726280 fix(templates): set correct minimum node version in package.json engines (#6835)
20.9.0 is the earliest v20 LTS and our minimum Node 20 version
2024-06-18 16:44:06 +00:00
Elliot DeNolf
a680e687b5 chore(release): v3.0.0-beta.51 [skip ci] 2024-06-18 12:25:56 -04:00
Alessio Gravili
b7d5a6a2a2 fix(ui): react-datepicker inserting invalid require("react") calls in our bundle (#6833) 2024-06-18 11:48:00 -04:00
Elliot DeNolf
040893ff22 fix: generated template imports (#6832)
Update templates with import breaking changes
2024-06-18 11:28:19 -04:00
Jarrod Flesch
cedd916816 fix: corrects permission access reading for disabling fields (#6815)
Fixes issues where access control was not properly affecting the read-only setting on fields.
2024-06-17 18:33:45 -04:00
Elliot DeNolf
45871489d0 chore(release): v3.0.0-beta.50 [skip ci] 2024-06-17 18:30:17 -04:00
Alessio Gravili
35a5d0cb3c fix(richtext-*): do not use different version of faceless-ui by importing prebundled faceless-ui from ui (#6816)
Fixes editor crashing when opening admin panel
2024-06-17 16:23:24 -04:00
Patrik
47ee40a3f4 fix(ui): basePath not handled for logout route (#6817)
## Description

Fixes an issue where if you define a `basePath` in your `next` config,
the logout button would redirect you to `/admin/logout` instead of
`/basePath/admin/logout` causing a 404.

- [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-06-17 16:23:07 -04:00
Elliot DeNolf
25968d43c2 chore(release): v3.0.0-beta.49 [skip ci] 2024-06-17 14:32:33 -04:00
Jacob Fletcher
9e76c8f4e3 feat!: prebundle payload, ui, richtext-lexical (#6579)
# Breaking Changes

### New file import locations

Exports from the `payload` package have been _significantly_ cleaned up.
Now, just about everything is able to be imported from `payload`
directly, rather than an assortment of subpath exports. This means that
things like `import { buildConfig } from 'payload/config'` are now just
imported via `import { buildConfig } from 'payload'`. The mental model
is significantly simpler for developers, but you might need to update
some of your imports.

Payload now exposes only three exports:

1. `payload` - all types and server-only Payload code
2. `payload/shared` - utilities that can be used in either the browser
or in Node environments
3. `payload/node` - heavy utilities that should only be imported in Node
scripts and never be imported into bundled code like Next.js

### UI library pre-bundling

With this release, we've dramatically sped up the compile time for
Payload by pre-bundling our entire UI package for use inside of the
Payload admin itself. There are new exports that should be used within
Payload custom components:

1. `@payloadcms/ui/client` - all client components 
2. `@payloadcms/ui/server` - all server components

For all of your custom Payload admin UI components, you should be
importing from one of these two pre-compiled barrel files rather than
importing from the more deeply nested exports directly. That will keep
compile times nice and speedy, and will also make sure that the bundled
JS for your admin UI is kept small.

For example, whereas before, if you imported the Payload `Button`, you
would have imported it like this:

```ts
import { Button } from '@payloadcms/ui/elements/Button'
```

Now, you would import it like this:

```ts
import { Button } from '@payloadcms/ui/client'
```

This is a significant DX / performance optimization that we're pretty
pumped about.

However, if you are importing or re-using Payload UI components
_outside_ of the Payload admin UI, for example in your own frontend
apps, you can import from the individual component exports which will
make sure that the bundled JS is kept to a minimum in your frontend
apps. So in your own frontend, you can continue to import directly to
the components that you want to consume rather than importing from the
pre-compiled barrel files.

Individual component exports will now come with their corresponding CSS
and everything will work perfectly as-expected.

### Specific exports have changed

- `'@payloadcms/ui/templates/Default'` and
`'@payloadcms/ui/templates/Minimal`' are now exported from
`'@payloadcms/next/templates'`
- Old: `import { LogOut } from '@payloadcms/ui/icons/LogOut'` new:
`import { LogOutIcon } from '@payloadcms/ui/icons/LogOut'`

## Background info

In effort to make local dev as fast as possible, we need to import as
few files as possible so that the compiler has less to process. One way
we've achieved this in the Admin Panel was to _remove_ all .scss imports
from all components in the `@payloadcms/ui` module using a build
process. This stripped all `import './index.scss'` statements out of
each component before injecting them into `dist`. Instead, it bundles
all of the CSS into a single `main.css` file, and we import _that_ at
the root of the app.

While this concept is _still_ the right solution to the problem, this
particular approach is not viable when using these components outside
the Admin Panel, where not only does this root stylesheet not exist, but
where it would also bloat your app with unused styles. Instead, we need
to _keep_ these .scss imports in place so they are imported directly
alongside your components, as expected. Then, we need create a _new_
build step that _separately_ compiles the components _without_ their
stylesheets—this way your app can consume either as needed from the new
`client` and `server` barrel files within `@payloadcms/ui`, i.e. from
within `@payloadcms/next` and all other admin-specific packages and
plugins.

This way, all other applications will simply import using the direct
file paths, just as they did before. Except now they come with
stylesheets.

And we've gotten a pretty awesome initial compilation performance boost.

---------

Co-authored-by: James <james@trbl.design>
Co-authored-by: Alessio Gravili <alessio@gravili.de>
2024-06-17 14:25:36 -04:00
Elliot DeNolf
3b3b1cecc5 chore(release): v3.0.0-beta.48 [skip ci] 2024-06-17 12:55:08 -04:00
Jacob Fletcher
6862b43261 docs: prepares docs for beta (#6808) 2024-06-17 11:44:25 -04:00
Paul
a3e1856bde fix: date hydration error if user locale is different to server (#6806)
Closes https://github.com/payloadcms/payload/issues/6796

## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
2024-06-17 15:16:58 +00:00
Alessio Gravili
6612bd1c98 fix(richtext-lexical): lexicalHTML field was persisted in database even though it should not (#6795) 2024-06-17 15:14:38 +00:00
Dan Ribbens
ce2ae9561d fix: loader windows path resolution (#6804) 2024-06-17 10:54:09 -04:00
Jarrod Flesch
1a03e9ace5 fix: prevent clearing of language selection on account view (#6803)
Fixes https://github.com/payloadcms/payload/issues/6794

Users should not be able to clear their language selection on the
account view.
2024-06-17 09:53:33 -04:00
Alessio Gravili
e7159c033e fix(ui,richtext-*): path from context should always have precedence over path from props, even if it's an empty string (#6782) 2024-06-15 05:42:16 +00:00
Alessio Gravili
628749573e fix(ui): properly type Select element onChange type, as well as any components using it (#6785) 2024-06-14 22:28:59 -04:00
Jarrod Flesch
0920c8a2f0 fix: array row validation messages (#6781) 2024-06-14 19:49:48 +00:00
Jarrod Flesch
680ed1dec8 fix: allows navigation to reset-pw route, adds customization for route (#6778)
Fixes https://github.com/payloadcms/payload/issues/6745

Fixes the inability to navigate to the reset password route. Adds the ability to customize the route and docs for all customizable admin panel routes.
2024-06-14 12:38:32 -04:00
Jarrod Flesch
ddc3ab534e fix: passes toast success and error handlers to form handleResponse fn (#6775)
Fixes https://github.com/payloadcms/payload/issues/6747

Passes successToast and errorToast through to the Form handleResponse
method.
2024-06-14 00:31:39 -04:00
Jarrod Flesch
7c35e8865c feat: prevent setting column preferences unless edited (#6774)
Fixes https://github.com/payloadcms/payload/issues/6458

Prevents setting column preferences unless they are manually changed.
2024-06-13 23:52:39 -04:00
Elliot DeNolf
8f6cedf67a chore(release): v3.0.0-beta.47 [skip ci] 2024-06-13 15:36:34 -04:00
Anders Semb Hermansen
7bb2e3be76 feat: adds X-HTTP-Method-Override header (#6487)
Fixes: https://github.com/payloadcms/payload/issues/6486

Adds `X-HTTP-Method-Override` header to allow for sending query params in the body of a POST request. This is useful when the query param string hits the upper limit.
2024-06-13 15:27:39 -04:00
Paul
78db50a497 feat(plugin-stripe): add full req object to stripe webhook handlers (#6770)
Provides `req` to the webhook handlers in Stripe plugin and fixes type
to `PayloadRequest` for req by default.
2024-06-13 19:00:11 +00:00
Jarrod Flesch
f36bf5e4e3 fix: adds translation for authentication:apiKey (#6771)
Fixes https://github.com/payloadcms/payload/issues/6697

Adds `authentication:apiKey` to client translations.
2024-06-13 14:57:58 -04:00
Elliot DeNolf
d10792452f docs: add disclaimer to migration guide 2024-06-13 14:34:51 -04:00
Elliot DeNolf
c500ac83b2 docs: rough draft of migration guide (#6769)
Rough draft of migration guide / breaking changes doc.
2024-06-13 14:23:49 -04:00
Jarrod Flesch
082650c0e2 fix: attempt to use user locale preference when not set as query param (#6761)
Fixes https://github.com/payloadcms/payload/issues/6619

Attempt to use user preference if available when loading view data instead of always relying on query param when loading view data.
2024-06-13 11:22:28 -04:00
Elliot DeNolf
11de4b037d feat!: use Gravatar for default avatar (#6765)
- Fixes #6725 . Gravatar and custom avatar components.
- Makes Gravatar the default
2024-06-13 15:01:44 +00:00
Viet-Tien
0162560996 fix: adds siteName to openGraphSchema joi validation (#6764) 2024-06-13 10:29:32 -04:00
Elliot DeNolf
ed0820f6c8 feat: warn if image resizing enabled but sharp is not passed to config (#6763)
Warning will now show if image resizing enabled, but sharp is not passed
to config.

Fixes #6755
2024-06-13 14:19:57 +00:00
Patrik
e148243260 fix(payload, ui): unable to save animated file types with undefined image sizes (#6757)
## Description

V2 PR [here](https://github.com/payloadcms/payload/pull/6733)

Additionally fixes issue with image thumbnails not updating properly
until page refresh.

Image thumbnails properly update on document save now.

- [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] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
2024-06-13 09:43:44 -04:00
Jacob Fletcher
8e56328e63 fix!: meta.icons type and schema validation (#6759) 2024-06-13 09:36:30 -04:00
Jacob Fletcher
019677b7e6 chore(eslint): consolidates and prevents duplicate imports (#6756)
## Description

Adds ESLint rule to consolidate duplicate imports using the
`import/no-duplicates` rule of the `eslint-plugin-import` plugin. More
here:
https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-duplicates.md.
This was needed as opposed to `no-duplicate-imports` because of the
auto-fix feature.
2024-06-12 16:45:43 -04:00
Elliot DeNolf
0d31021c25 chore(release): v3.0.0-beta.46 [skip ci] 2024-06-12 16:21:26 -04:00
Jarrod Flesch
8e9ed2ebe3 chore: corrects admin.meta joi validation (#6754) 2024-06-12 16:16:23 -04:00
Jessica Chowdhury
763a34f19b fix: corrects block duplicate action and add tests (#6589) 2024-06-12 14:44:17 -04:00
Elliot DeNolf
be0462db56 feat: diff generated types before write (#6749)
Diff types on disk before write
2024-06-12 14:16:03 -04:00
Elliot DeNolf
6e55a2e52d fix: unawaited emails (#6265)
Await email sending, serverless may end before send

Fixes #6457
2024-06-12 14:02:05 -04:00
Alessio Gravili
4e127054ca feat(richtext-lexical)!: sub-field hooks and localization support (#6591)
## BREAKING
- Our internal field hook methods now have new required `schemaPath` and
path `props`. This affects the following functions, if you are using
those: `afterChangeTraverseFields`, `afterReadTraverseFields`,
`beforeChangeTraverseFields`, `beforeValidateTraverseFields`,
`afterReadPromise`
- The afterChange field hook's `value` is now the value AFTER the
previous hooks were run. Previously, this was the original value, which
I believe is a bug
- Only relevant if you have built your own richText adapter: the
richText adapter `populationPromises` property has been renamed to
`graphQLPopulationPromises` and is now only run for graphQL. Previously,
it was run for graphQL AND the rest API. To migrate, use
`hooks.afterRead` to run population for the rest API
- Only relevant if you have built your own lexical features: The
`populationPromises` server feature property has been renamed to
`graphQLPopulationPromises` and is now only run for graphQL. Previously,
it was run for graphQL AND the rest API. To migrate, use
`hooks.afterRead` to run population for the rest API
- Serialized lexical link and upload nodes now have a new `id` property.
While not breaking, localization / hooks will not work for their fields
until you have migrated to that. Re-saving the old document on the new
version will automatically add the `id` property for you. You will also
get a bunch of console logs for every lexical node which is not migrated
2024-06-12 13:33:08 -04:00
Elliot DeNolf
27510bb963 chore(templates): fix vercel one click links [skip ci] 2024-06-11 16:30:11 -04:00
Anders Semb Hermansen
de45e6094b fix(ui): hideGutter was ignored in group field (#6613) 2024-06-11 16:26:00 -04:00
Patryk Kowalczyk
74159de1ec fix: add missing export for useLeaf hook (#6693) 2024-06-11 16:12:25 -04:00
Jarrod Flesch
ba92d864bb fix: list sort preferences (#6731)
Fixes https://github.com/payloadcms/payload/issues/6617

Sets preferences when list sort is set. Uses defaultSort when defined in
config and preferences are not set.
2024-06-11 16:02:28 -04:00
Elliot DeNolf
0fb14cfebe chore(release): v3.0.0-beta.45 [skip ci] 2024-06-11 15:09:41 -04:00
Paul
2ada6fc58d fix: toasts padding and button placement by 1px (#6730)
## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)
2024-06-11 18:42:17 +00:00
Alessio Gravili
cb3355b30f feat!: move from react-toastify to sonner (#6682)
**BREAKING:** We now export toast from `sonner` instead of
`react-toastify`. If you send out toasts from your own projects, make
sure to use our `toast` export, or install `sonner`. React-toastify
toasts will no longer work anymore. The Toast APIs are mostly similar,
but there are some differences if you provide options to your toast

CSS styles have been changed from Toastify

```css
/* before */
.Toastify


/* current */
.payload-toast-container
.payload-toast-item
.payload-toast-close-button

/* individual toast items will also have these classes depending on the state */
.toast-info
.toast-warning
.toast-success
.toast-error
```


https://github.com/payloadcms/payload/assets/70709113/da3e732e-aafc-4008-9469-b10f4eb06b35

---------

Co-authored-by: Paul Popus <paul@nouance.io>
2024-06-11 14:12:59 -04:00
Patrik
10c6ffafc3 fix: only use metadata.pages for height if animated (#6728)
## Description

### Issue: 

Non-animated webp / gif files were using `metadata.pages` to calculate
it's resized heights for `imageSizes` or `cropping`.

### Fix: 

It should only use this to calculate it's height if the file's
`metadata` contains `metadata.pages`. Non-animated webps and gifs would
not have this.

- [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-06-11 13:45:49 -04:00
Patrik
6512d5ce69 fix: create sharp file for fileHasAdjustments files or fileIsAnimated files (#6708)
## Description

Fixes #6694 

Previously we were only creating sharp files for files that have file
adjustments but instead a sharp file should be created for animated
images even if there are no file adjustments - i.e

`const fileHasAdjustments = fileSupportsResize && Boolean(resizeOptions
|| formatOptions || imageSizes || trimOptions || file.tempFilePath)`

- [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-06-11 10:55:51 -04:00
Jarrod Flesch
57fcc9148e fix: corrects field-paths that were incorrectly being set (#6724)
Fixes https://github.com/payloadcms/payload/issues/6650

Similar to [6712](https://github.com/payloadcms/payload/pull/6712). Field paths were
not accounting for the 4 scenarios:
- both parentPath & fieldName
- only parentPath
- only fieldName
- neither parentPath or fieldName (top level rows, etc)
2024-06-11 10:17:40 -04:00
Elliot DeNolf
36f4f23463 chore(release): v3.0.0-beta.44 [skip ci] 2024-06-11 09:46:31 -04:00
Alessio Gravili
7b7dc71845 fix: get auto type-gen to work on turbo, by running type gen in a child process outside turbo/webpack (#6714)
Before on turbo: https://github.com/vercel/next.js/issues/66723
2024-06-10 22:03:12 +00:00
Jarrod Flesch
ba513d5a97 fix: corrects tab paths when nested within other row like fields (#6712)
Fixes https://github.com/payloadcms/payload/issues/6637

There was an issue where tab paths were being generated based on 2
scenarios when there are 3 possible scenarios:
- A path is provided and the tab is named
- A path is **not** provided but the tab is named
- Neither a path or a tab name are provided
2024-06-10 16:06:09 -04:00
Jarrod Flesch
a26d03190e fix: re-exports graphql json types for external use (#6711)
Fixes https://github.com/payloadcms/payload/issues/6683

Exports import `GraphQLJSON` and `GraphQLJSONObject` from
`@payloadcms/graphql/types`

```ts
import { GraphQLJSON, GraphQLJSONObject } from '@payloadcms/graphql/types'
```
2024-06-10 14:53:31 -04:00
Patrik
9f525621c8 fix(ui): removes array & blocks & group fields from sort (#6576)
## Description

V2 PR [here](https://github.com/payloadcms/payload/pull/6574)

- [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-06-10 14:09:50 -04:00
Elliot DeNolf
7309d474ee feat!: type auto-generation (#6657)
Types are now auto-generated by default.

You can opt-out of this behavior by setting:
```ts
buildConfig({
  // Rest of config
  typescript: {
    autoGenerate: false
  },
})
```
2024-06-10 13:42:44 -04:00
Jarrod Flesch
45e86832c2 fix: global draft validations (#6709)
- Extends draft validation from https://github.com/payloadcms/payload/pull/6677 to work with globals as
well

- Fixes bug from https://github.com/payloadcms/payload/pull/6677 where
autosave was not saving properly after first autosave
2024-06-10 12:31:22 -04:00
Alessio Gravili
1bd91b23ca chore: improved clean commands which work on windows and output pretty summary (#6685) 2024-06-09 05:21:11 +00:00
Alessio Gravili
ac34380eb8 fix(ui): set checkbox htmlFor by default, fixing some checkbox labels not toggling the checkbox (#6684) 2024-06-08 19:34:26 +00:00
Jacob Fletcher
17707852e0 chore: migrates @faceless-ui imports to esm (#6681) 2024-06-07 22:59:39 -04:00
Elliot DeNolf
8b95218577 chore(release): v3.0.0-beta.43 [skip ci] 2024-06-07 17:45:28 -04:00
Jarrod Flesch
a79d23c631 chore: adjusts test config for draft validation (#6678) 2024-06-07 16:01:03 -04:00
Jarrod Flesch
52c81ad525 feat: adds draft validation option (#6677)
## Description

Allows draft validation to be enabled at the config level.

You can enable this by:
```ts
// ...collectionConfig
versions: {
  drafts: {
    validate: true // defaults to false
  }
}
```
2024-06-07 15:22:03 -04:00
Paul
8ec836737e chore: add turbo resolveAlias mock alias to hide webpack warnings (#6676) 2024-06-07 17:23:35 +00:00
Paul
e4a90294ea feat(plugin-redirects)!: update fields overrides to use a function (#6675)
## Description

Updates the `fields` override in plugin redirects to allow for
overriding

```ts
// before
overrides: {
  fields: [
    {
      type: 'text',
      name: 'customField',
    },
  ],
},

// current
overrides: {
  fields: ({ defaultFields }) => {
    return [
      ...defaultFields,
      {
        type: 'text',
        name: 'customField',
      },
    ]
  },
},
```


## Type of change

- [x] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
2024-06-07 14:41:09 +00:00
Jacob Fletcher
7c8d562f03 fix(next): live preview device position when using zoom (#6665) 2024-06-07 10:17:49 -04:00
Jacob Fletcher
a20cf70105 docs: removes express 2024-05-13 10:29:59 -04:00
Jacob Fletcher
0886e4e972 docs: restructures admin components docs 2024-05-10 17:56:11 -04:00
Jacob Fletcher
550a40d6a2 docs: updates admin overview doc 2024-05-10 15:28:14 -04:00
Jacob Fletcher
261f6dc20d docs: adds examples docs 2024-05-10 10:00:14 -04:00
Jacob Fletcher
1a20390454 docs: removes bundlers, webpack, and vite 2024-05-09 15:58:51 -04:00
1606 changed files with 22000 additions and 14427 deletions

5
.gitignore vendored
View File

@@ -12,6 +12,11 @@ test-results
.localstack
.turbo
meta_client.json
meta_server.json
meta_index.json
meta_shared.json
.turbo
# Ignore test directory media folder/files

1
.idea/payload.iml generated
View File

@@ -74,6 +74,7 @@
<excludeFolder url="file://$MODULE_DIR$/packages/translations/dist" />
<excludeFolder url="file://$MODULE_DIR$/packages/ui/.swc" />
<excludeFolder url="file://$MODULE_DIR$/packages/ui/.turbo" />
<excludeFolder url="file://$MODULE_DIR$/packages/ui/dist" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

7
.vscode/launch.json vendored
View File

@@ -111,6 +111,13 @@
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js field-error-states",
"cwd": "${workspaceFolder}",
"name": "Run Dev Field Error States",
"request": "launch",
"type": "node-terminal"
},
{
"command": "pnpm run test:int live-preview",
"cwd": "${workspaceFolder}",

View File

@@ -1,6 +1,7 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
import configPromise from '@payload-config'
import { RootLayout } from '@payloadcms/next/layouts'
// import '@payloadcms/ui/styles.css' // Uncomment this line if `@payloadcms/ui/client` in `tsconfig.json` points to `/ui/dist` instead of `/ui/src`
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import React from 'react'

View File

@@ -3,7 +3,7 @@ title: Collection Access Control
label: Collections
order: 20
desc: With Collection-level Access Control you can define which users can create, read, update or delete Collections.
keywords: collections, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: collections, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
You can define Collection-level Access Control within each Collection's `access` property. All Access Control functions accept one `args` argument.
@@ -51,10 +51,10 @@ Returns a boolean which allows/denies access to the `create` request.
**Available argument properties:**
| Option | Description |
| ---------- | -------------------------------------------------------------------------- |
| **`req`** | The Express `request` object containing the currently authenticated `user` |
| **`data`** | The data passed to create the document with. |
| Option | Description |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`data`** | The data passed to create the document with. |
**Example:**
@@ -80,7 +80,7 @@ Read access functions can return a boolean result or optionally return a [query
| Option | Description |
| --------- | -------------------------------------------------------------------------- |
| **`req`** | The Express `request` object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`id`** | `id` of document requested, if within `findByID` |
**Example:**
@@ -111,7 +111,7 @@ Update access functions can return a boolean result or optionally return a [quer
| Option | Description |
| ---------- | -------------------------------------------------------------------------- |
| **`req`** | The Express `request` object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`id`** | `id` of document requested to update |
| **`data`** | The data passed to update the document with |
@@ -138,7 +138,7 @@ Similarly to the Update function, returns a boolean or a [query constraint](/doc
| Option | Description |
| --------- | --------------------------------------------------------------------------------------------------- |
| **`req`** | The Express `request` object with additional `user` property, which is the currently logged in user |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object with additional `user` property, which is the currently logged in user |
| **`id`** | `id` of document requested to delete |
**Example:**
@@ -173,7 +173,7 @@ If the Collection is [used to access the Payload Admin panel](/docs/admin/overvi
| Option | Description |
| --------- | -------------------------------------------------------------------------- |
| **`req`** | The Express `request` object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
### Unlock
@@ -183,4 +183,4 @@ Determines which users can [unlock](/docs/authentication/operations#unlock) othe
| Option | Description |
| --------- | -------------------------------------------------------------------------- |
| **`req`** | The Express `request` object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |

View File

@@ -3,7 +3,7 @@ title: Field-level Access Control
label: Fields
order: 30
desc: Field-level Access Control is specified within a field's config, and allows you to define which users can create, read or update Fields.
keywords: fields, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: fields, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Field Access Control is specified with functions inside a field's config. All field-level Controls return a boolean value to allow or deny access for the specified operation. No field-level Access Controls support returning query constraints. All Access Control functions accept one `args` argument.
@@ -47,7 +47,7 @@ Returns a boolean which allows or denies the ability to set a field's value when
| Option | Description |
| ----------------- | -------------------------------------------------------------------------- |
| **`req`** | The Express `request` object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`data`** | The full data passed to create the document. |
| **`siblingData`** | Immediately adjacent field data passed to create the document. |
@@ -59,7 +59,7 @@ Returns a boolean which allows or denies the ability to read a field's value. If
| Option | Description |
| ----------------- | -------------------------------------------------------------------------- |
| **`req`** | The Express `request` object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`id`** | `id` of the document being read |
| **`doc`** | The full document data. |
| **`siblingData`** | Immediately adjacent field data of the document being read. |
@@ -74,7 +74,7 @@ If `false` is returned and you attempt to update the field's value, the operatio
| Option | Description |
| ----------------- | -------------------------------------------------------------------------- |
| **`req`** | The Express `request` object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`id`** | `id` of the document being updated |
| **`data`** | The full data passed to update the document. |
| **`siblingData`** | Immediately adjacent field data passed to update the document with. |

View File

@@ -3,7 +3,7 @@ title: Globals Access Control
label: Globals
order: 40
desc: Global-level Access Control is specified within each Global's `access` property and allows you to define which users can read or update Globals.
keywords: globals, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: globals, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
You can define Global-level Access Control within each Global's `access` property. All Access Control functions accept one `args` argument.
@@ -45,7 +45,7 @@ Returns a boolean result or optionally a [query constraint](/docs/queries/overvi
| Option | Description |
| --------- | -------------------------------------------------------------------------- |
| **`req`** | The Express `request` object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
### Update
@@ -55,5 +55,5 @@ Returns a boolean result or optionally a [query constraint](/docs/queries/overvi
| Option | Description |
| ---------- | -------------------------------------------------------------------------- |
| **`req`** | The Express `request` object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`data`** | The data passed to update the global with. |

View File

@@ -3,7 +3,7 @@ title: Access Control
label: Overview
order: 10
desc: Payload makes it simple to define and manage access control. By declaring roles, you can set permissions and restrict what your users can interact with.
keywords: overview, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: overview, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Access control within Payload is extremely powerful while remaining easy and intuitive to manage. Declaring who should have access to what documents is no more complex than writing a simple JavaScript function that either returns a `boolean` or a [`query`](/docs/queries/overview) constraint to restrict which documents users can interact with.
@@ -21,7 +21,7 @@ Access control within Payload is extremely powerful while remaining easy and int
## Default Settings
**By default, all Collections and Globals require that a user is logged in to be able to interact in any way.** The default Access Control function evaluates the `user` from the Express `req` and returns `true` if a user is logged in, and `false` if not.
**By default, all Collections and Globals require that a user is logged in to be able to interact in any way.** The default Access Control function evaluates the `user` from the `req` and returns `true` if a user is logged in, and `false` if not.
**Default Access function:**
@@ -37,9 +37,11 @@ const defaultPayloadAccess = ({ req: { user } }) => {
<strong>Note:</strong>
<br />
In the Local API, all Access Control functions are skipped by default, allowing your server to do
whatever it needs. But, you can opt back in by setting the option <strong>
whatever it needs. But, you can opt back in by setting the option
<strong>
overrideAccess
</strong>{' '}
</strong>
{' '}
to <strong>false</strong>.
</Banner>

View File

@@ -1,54 +0,0 @@
---
title: Bundlers
label: Bundlers
order: 60
desc: Bundlers are used to bundle the code that serves Payload's Admin Panel.
---
Payload has two official bundlers, the [Webpack Bundler](/docs/admin/webpack) and the [Vite Bundler](/docs/admin/vite). You must install a bundler to use the admin panel.
## Install a bundler
Webpack (recommended):
```text
yarn add @payloadcms/bundler-webpack
```
Vite (beta):
```text
yarn add @payloadcms/bundler-vite
```
## Configure the bundler
```ts
// payload.config.ts
import { buildConfig } from 'payload/config'
import { webpackBundler } from '@payloadcms/bundler-webpack'
// import { viteBundler } from '@payloadcms/bundler-vite'
export default buildConfig({
// highlight-start
admin: {
bundler: webpackBundler(), // or viteBundler()
},
// highlight-end
})
```
## What are bundlers?
At their core, a bundler's main goal is to take a bunch of files and turn them into a few optimized files that you ship to the browser. The admin UI has a root `index.html` entry point, and from there the bundler traverses the dependency tree, bundling all of the files that are required from that point on.
Since the bundled file is sent to the browser, it can't include any server-only code. You will need to remove any server-only code from your admin UI before bundling it. You can learn more about [excluding server code](/docs/admin/excluding-server-code) section.
<Banner type="warning">
<strong>Using environment variables in the admin UI</strong>
<br />
Bundles should not contain sensitive information. By default, Payload excludes env variables from
the bundle. If you need to use env variables in your payload config, you need to prefix them with
`PAYLOAD_PUBLIC_` to make them available to the client-side code.
</Banner>

View File

@@ -3,12 +3,16 @@ title: Swap in your own React components
label: Custom Components
order: 20
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, express
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
While designing the Payload Admin panel, we determined it should be as minimal and straightforward as possible to allow easy customization and control. There are many times where you may want to completely control how a whole view or a field works. You might even want to add in new views entirely. In order for Payload to support this level of customization without introducing versioning / future-proofing issues, Payload provides for a pattern to supply your own React components via your Payload config.
The [Payload Admin](./overview) panel is designed to be as minimal and straightforward as possible to allow easy customization and control. In order for Payload to support this level of customization without introducing versioning or future-proofing issues, Payload provides a pattern for you to supply your own React components via your Payload config.
To swap in your own React component, first, consult the list of available component overrides below. Determine the scope that corresponds to what you are trying to accomplish, and then author your React component accordingly.
<Banner type="warning">
All Custom Components in the Admin Panel are [React Server Components](https://react.dev/reference/rsc/server-components). This means they are rendered on the server
</Banner>
To swap in your own React component, first, consult the list of available components below. Determine the scope that corresponds to what you are trying to accomplish, and then author your React component accordingly.
<Banner type="success">
<strong>Tip:</strong>
@@ -33,9 +37,9 @@ You can override a set of admin panel-wide components by providing a component t
| **`logout.Button`** | A custom React component. |
| **`graphics.Icon`** | Used as a graphic within the `Nav` component. Often represents a condensed version of a full logo. |
| **`graphics.Logo`** | The full logo to be used in contexts like the `Login` view. |
| **`providers`** | Define your own provider components that will wrap the Payload Admin UI. [More](#custom-providers) |
| **`actions`** | Array of custom components to be rendered in the Payload Admin UI header, providing additional interactivity and functionality. |
| **`views`** | Override or create new views within the Payload Admin UI. [More](#views) |
| **`providers`** | Define your own provider components that will wrap the [Admin Panel](./overview). [More](#custom-providers) |
| **`actions`** | Array of custom components to be rendered in the [Admin Panel](./overview) header, providing additional interactivity and functionality. |
| **`views`** | Override or create new [Views](./views) within the [Admin Panel](./overview). |
Here is a full example showing how to swap some of these components for your own.
@@ -73,78 +77,6 @@ export default buildConfig({
})
```
### Views
You can easily swap entire views with your own by using the `admin.components.views` property. At the root level, Payload renders the following views by default, all of which can be overridden:
| Property | Description |
| --------------- | ----------------------------------------------------------------------------- |
| **`Account`** | The Account view is used to show the currently logged in user's Account page. |
| **`Dashboard`** | The main landing page of the Admin panel. |
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. For example:
```ts
// payload.config.ts
{
// ...
admin: {
components: {
views: {
Account: MyCustomAccountView,
Dashboard: MyCustomDashboardView,
},
},
},
}
```
For more granular control, pass a configuration object instead. Each view corresponds to its own `<Route />` component in [React Router v5](https://v5.reactrouter.com). Payload exposes all of the properties of React Router:
| Property | Description |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| **`Component`** \* | Pass in the component that should be rendered when a user navigates to this route. |
| **`path`** \* | React Router `path`. [See the React Router docs](https://v5.reactrouter.com/web/api/Route/path-string-string) for more info. |
| **`exact`** | React Router `exact` property. [More](https://v5.reactrouter.com/web/api/Route/exact-bool) |
| **`strict`** | React Router `strict` property. [More](https://v5.reactrouter.com/web/api/Route/strict-bool) |
| **`sensitive`** | React Router `sensitive` property. [More](https://v5.reactrouter.com/web/api/Route/sensitive-bool) |
_\* An asterisk denotes that a property is required._
### Adding new views
To add a _new_ view to the Admin Panel, simply add another key to the `views` object with at least a `path` and `Component` property. For example:
```ts
// payload.config.ts
{
// ...
admin: {
components: {
views: {
MyCustomView: {
Component: MyCustomView,
path: '/my-custom-view',
},
},
},
},
}
```
<Banner type="warning">
<strong>Note:</strong>
<br />
Routes are cascading. This means that unless explicitly given the `exact` property, they will
match on URLs that simply _start_ with the route's path. This is helpful when creating catch-all
routes in your application. Alternatively, you could define your nested route _before_ your parent
route.
</Banner>
_For more examples regarding how to customize components, look at the following [examples](https://github.com/payloadcms/payload/tree/main/test/admin/components)._
For help on how to build your own custom view components, see [building a custom view component](#building-a-custom-view-component).
## Collections
You can override components on a collection-by-collection basis via the `admin.components` property.
@@ -159,25 +91,33 @@ You can override components on a collection-by-collection basis via the `admin.c
| **`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 Payload Admin UI. [More](#collection-views) |
| **`views`** | Override or create new [Views](./views) within the [Admin Panel](./overview). |
Here is a full example showing how to swap some of these components for your own:
`Collection.ts`
`CustomSaveButton.tsx`
```tsx
import * as React from 'react'
import { CustomSaveButtonProps } from 'payload/types'
import {
CustomSaveButtonProps,
CustomSaveDraftButtonProps,
CustomPublishButtonProps,
CustomPreviewButtonProps,
} from 'payload/types'
export const CustomSaveButton: CustomSaveButtonProps = ({ DefaultButton, label, save }) => {
return <DefaultButton label={label} save={save} />
const CustomSaveButton: CustomSaveButtonProps = ({
DefaultButton,
label,
save
}) => {
return (
<DefaultButton
label={label}
save={save}
/>
)
}
```
`CustomSaveDraftButton.tsx`
```tsx
import { CustomSaveDraftButtonProps } from 'payload/types'
export const CustomSaveDraftButton: CustomSaveDraftButtonProps = ({
DefaultButton,
@@ -185,8 +125,20 @@ export const CustomSaveDraftButton: CustomSaveDraftButtonProps = ({
label,
saveDraft,
}) => {
return <DefaultButton label={label} disabled={disabled} saveDraft={saveDraft} />
return (
<DefaultButton
label={label}
disabled={disabled}
saveDraft={saveDraft}
/>
)
}
```
`CustomPublishButton.tsx`
```tsx
import { CustomPreviewButtonProps } from 'payload/types'
export const CustomPublishButton: CustomPublishButtonProps = ({
DefaultButton,
@@ -194,8 +146,20 @@ export const CustomPublishButton: CustomPublishButtonProps = ({
label,
publish,
}) => {
return <DefaultButton label={label} disabled={disabled} publish={publish} />
return (
<DefaultButton
label={label}
disabled={disabled}
publish={publish}
/>
)
}
```
`CustomPreviewButton`
```tsx
import { CustomPreviewButtonProps } from 'payload/types'
export const CustomPreviewButton: CustomPreviewButtonProps = ({
DefaultButton,
@@ -203,8 +167,25 @@ export const CustomPreviewButton: CustomPreviewButtonProps = ({
label,
preview,
}) => {
return <DefaultButton label={label} disabled={disabled} preview={preview} />
return (
<DefaultButton
label={label}
disabled={disabled}
preview={preview}
/>
)
}
```
`collection.ts`
```tsx
import * as React from 'react'
import { CustomSaveButton } from './CustomSaveButton'
import { CustomSaveDraftButton } from './CustomSaveDraftButton'
import { CustomPublishButton } from './CustomPublishButton'
import { CustomPreviewButton } from './CustomPreviewButton'
export const MyCollection: SanitizedCollectionConfig = {
slug: 'my-collection',
@@ -221,82 +202,6 @@ export const MyCollection: SanitizedCollectionConfig = {
}
```
### Collection views
To swap out entire views on collections, you can use the `admin.components.views` property on the collection's config. Payload renders the following views by default, all of which can be overridden:
| Property | Description |
| ---------- | ------------------------------------------------------------------------- |
| **`Edit`** | The Edit view is used to edit a single document for a given collection. |
| **`List`** | The List view is used to show a list of documents for a given collection. |
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, tabs, etc, _as well as all nested routes_.
```ts
// Collection.ts
{
// ...
admin: {
components: {
views: {
Edit: MyCustomEditView,
List: MyCustomListView,
},
},
},
}
```
_For help on how to build your own custom view components, see [building a custom view component](#building-a-custom-view-component)._
**Customizing Nested Views within 'Edit' in Collections**
The `Edit` view in collections consists of several nested views, each serving a unique purpose. You can customize these nested views using the `admin.components.views.Edit` property in the collection's configuration. This approach allows you to replace specific nested views while keeping the overall structure of the `Edit` view intact, including the page breadcrumbs, title, tabs, etc.
Here's an example of how you can customize nested views within the `Edit` view in collections, including the use of the `actions` property:
```ts
// Collection.ts
{
// ...
admin: {
components: {
views: {
Edit: {
Default: {
Component: MyCustomDefaultTab,
actions: [CollectionEditButton], // Custom actions for the default edit view
},
API: {
Component: MyCustomAPIView,
actions: [CollectionAPIButton], // Custom actions for API view
},
LivePreview: {
Component: MyCustomLivePreviewView,
actions: [CollectionLivePreviewButton], // Custom actions for Live Preview
},
Version: {
Component: MyCustomVersionView,
actions: [CollectionVersionButton], // Custom actions for Version view
},
Versions: {
Component: MyCustomVersionsView,
actions: [CollectionVersionsButton], // Custom actions for Versions view
},
},
List: {
actions: [CollectionListButton],
},
},
},
},
}
```
**Adding New Tabs to 'Edit' View**
You can also add _new_ tabs to the `Edit` view by adding another key to the `components.views.Edit[key]` object with a `path` and `Component` property. See [Custom Tabs](#custom-tabs) for more information.
## Globals
As with Collections, you can override components on a global-by-global basis via the `admin.components` property.
@@ -307,362 +212,11 @@ As with Collections, you can override components on a global-by-global basis via
| **`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 Payload Admin UI. [More](#global-views) |
### Global views
To swap out views for globals, you can use the `admin.components.views` property on the global's config. Payload renders the following views by default, all of which can be overridden:
| Property | Description |
| ---------- | ------------------------------------------------------------------- |
| **`Edit`** | The Edit view is used to edit a single document for a given Global. |
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, and tabs, _as well as all nested views_.
```ts
// Global.ts
{
// ...
admin: {
components: {
views: {
Edit: MyCustomEditView,
},
},
},
}
```
_For help on how to build your own custom view components, see [building a custom view component](#building-a-custom-view-component)._
**Customizing Nested Views within 'Edit' in Globals**
Similar to collections, Globals allow for detailed customization within the `Edit` view. This includes the ability to swap specific nested views while maintaining the overall structure of the `Edit` view. You can use the `admin.components.views.Edit` property in the Globals configuration to achieve this, and this will only replace the nested view, leaving the page breadcrumbs, title, and tabs intact.
Here's how you can customize nested views within the `Edit` view in Globals, including the use of the `actions` property:
```ts
// Global.ts
{
// ...
admin: {
components: {
views: {
Edit: {
Default: {
Component: MyCustomGlobalDefaultTab,
actions: [GlobalEditButton], // Custom actions for the default edit view
},
API: {
Component: MyCustomGlobalAPIView,
actions: [GlobalAPIButton], // Custom actions for API view
},
LivePreview: {
Component: MyCustomGlobalLivePreviewView,
actions: [GlobalLivePreviewButton], // Custom actions for Live Preview
},
Version: {
Component: MyCustomGlobalVersionView,
actions: [GlobalVersionButton], // Custom actions for Version view
},
Versions: {
Component: MyCustomGlobalVersionsView,
actions: [GlobalVersionsButton], // Custom actions for Versions view
},
},
},
},
},
}
```
You can also add _new_ tabs to the `Edit` view by adding another key to the `components.views.Edit[key]` object with a `path` and `Component` property. See [Custom Tabs](#custom-tabs) for more information.
## Custom Tabs
You can easily swap individual collection or global edit views. To do this, pass an _object_ to the `admin.components.views.Edit` property of the config. Payload renders the following views by default, all of which can be overridden:
| Property | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------- |
| **`Default`** | The Default view is the primary view in which your document is edited. |
| **`Versions`** | The Versions view is used to view the version history of a single document. [More details](../versions) |
| **`Version`** | The Version view is used to view a single version of a single document for a given collection. [More details](../versions). |
| **`API`** | The API view is used to display the REST API JSON response for a given document. |
| **`LivePreview`** | The LivePreview view is used to display the Live Preview interface. [More details](../live-preview) |
Here is an example:
```ts
// Collection.ts or Global.ts
export const MyCollection: SanitizedCollectionConfig = {
slug: 'my-collection',
admin: {
components: {
views: {
Edit: {
// You can also define `components.views.Edit` as a component, this will override _all_ nested views
Default: MyCustomDefaultTab,
Versions: MyCustomVersionsTab,
Version: MyCustomVersionTab,
API: MyCustomAPITab,
LivePreview: MyCustomLivePreviewTab,
},
},
},
},
}
```
To add a _new_ tab to the `Edit` view, simply add another key to `components.views.Edit[key]` with at least a `path` and `Component` property. For example:
```ts
// `Collection.ts` or `Global.ts`
export const MyCollection: SanitizedCollectionConfig = {
slug: 'my-collection',
admin: {
components: {
views: {
Edit: {
MyCustomTab: {
Component: MyCustomTab,
path: '/my-custom-tab',
// You an swap the entire tab component out for your own
Tab: MyCustomTab,
},
AnotherCustomView: {
Component: AnotherCustomView,
path: '/another-custom-view',
// Or you can use the default tab component and just pass in your own label and href
Tab: {
label: 'Another Custom View',
href: '/another-custom-view',
},
},
},
},
},
},
}
```
## Building a custom view component
Your custom view components will be given all the props that a React Router `<Route />` typically would receive, as well as two props from Payload:
| Prop | Description |
| ----------------------- | ---------------------------------------------------------------------------- |
| **`user`** | The currently logged in user. Will be `null` if no user is logged in. |
| **`canAccessAdmin`** \* | If the currently logged in user is allowed to access the admin panel or not. |
<Banner type="warning">
<strong>Note:</strong>
<br />
It's up to you to secure your custom views. If your view requires a user to be logged in or to
have certain access rights, you should handle that within your view component yourself.
</Banner>
#### Example
You can find examples of custom views in the [Payload source code `/test/admin/components/views` folder](https://github.com/payloadcms/payload/tree/main/test/admin/components/views). There, you'll find two custom views:
1. A custom view that uses the `DefaultTemplate`, which is the built-in Payload template that displays the sidebar and "eyebrow nav"
1. A custom view that uses the `MinimalTemplate` - which is just a centered template used for things like logging in or out
To see how to pass in your custom views to create custom views of your own, take a look at the `admin.components.views` property of the [Payload test admin config](https://github.com/payloadcms/payload/blob/main/test/admin/config.ts).
## Fields
All Payload fields support the ability to swap in your own React components. So, for example, instead of rendering a default Text input, you might need to render a color picker that provides the editor with a custom color picker interface to restrict the data entered to colors only.
<Banner type="success">
<strong>Tip:</strong>
<br />
Don't see a built-in field type that you need? Build it! Using a combination of custom validation
and custom components, you can override the entirety of how a component functions within the admin
panel and effectively create your own field type.
</Banner>
**Fields support the following custom components:**
| Component | Description |
| ------------ | --------------------------------------------------------------------------------------------------------------------------- |
| **`Filter`** | Override the text input that is presented in the `List` view when a user is filtering documents by the customized field. |
| **`Cell`** | Used in the `List` view's table to represent a table-based preview of the data stored in the field. [More](#cell-component) |
| **`Field`** | Swap out the field itself within all `Edit` views. [More](#field-component) |
As an alternative to replacing the entire Field component, you may want to keep the majority of the default Field component and only swap components within. This allows you to replace the **`Label`** or **`Error`** within a field component or add additional components inside the field with **`beforeInput`** or **`afterInput`**. **`beforeInput`** and **`afterInput`** are allowed in any fields that don't contain other fields, except [UI](/docs/fields/ui) and [Rich Text](/docs/fields/rich-text).
| Component | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------- |
| **`Label`** | Override the default Label in the Field Component. [More](#label-component) |
| **`Error`** | Override the default Label in the Field Component. [More](#error-component) |
| **`beforeInput`** | An array of elements that will be added before `input`/`textarea` elements. [More](#afterinput-and-beforeinput) |
| **`afterInput`** | An array of elements that will be added after `input`/`textarea` elements. [More](#afterinput-and-beforeinput) |
## Cell Component
These are the props that will be passed to your custom Cell to use in your own components.
| Property | Description |
| ---------------- | ----------------------------------------------------------------- |
| **`field`** | An object that includes the field configuration. |
| **`colIndex`** | A unique number for the column in the list. |
| **`collection`** | An object with the config of the collection that the field is in. |
| **`cellData`** | The data for the field that the cell represents. |
| **`rowData`** | An object with all the field values for the row. |
#### Example
```tsx
import React from 'react'
import type { Props } from 'payload/components/views/Cell'
import './index.scss'
const baseClass = 'custom-cell'
const CustomCell: React.FC<Props> = (props) => {
const { field, colIndex, collection, cellData, rowData } = props
return <span className={baseClass}>{cellData}</span>
}
```
## Field Component
When writing your own custom components you can make use of a number of hooks to set data, get reactive changes to other fields, get the id of the document or interact with a context from a custom provider.
## Sending and receiving values from the form
When swapping out the `Field` component, you'll be responsible for sending and receiving the field's `value` from the form itself. To do so, import the `useField` hook as follows:
```tsx
import { useField } from 'payload/components/forms'
const CustomTextField: React.FC<{ path: string }> = ({ path }) => {
// highlight-start
const { value, setValue } = useField<string>({ path })
// highlight-end
return <input onChange={(e) => setValue(e.target.value)} value={value} />
}
```
<Banner type="success">
For more information regarding the hooks that are available to you while you build custom
components, including the <strong>useField</strong> hook, [click here](/docs/admin/hooks).
</Banner>
## Label Component
These are the props that will be passed to your custom Label.
| Property | Description |
| -------------- | ---------------------------------------------------------------- |
| **`htmlFor`** | Property used to set `for` attribute for label. |
| **`label`** | Label value provided in field, it can be used with i18n. |
| **`required`** | A boolean value that represents if the field is required or not. |
#### Example
```tsx
'use client'
import React from 'react'
import { getTranslation } from '@payloadcms/translations'
import { useTranslation } from '@payloadcms/ui/providers/Translation'
type Props = {
htmlFor?: string
label?: Record<string, string> | false | string
required?: boolean
}
const CustomLabel: React.FC<Props> = (props) => {
const { htmlFor, label, required = false } = props
const { i18n } = useTranslation()
if (label) {
return (
<span>
{getTranslation(label, i18n)}
{required && <span className="required">*</span>}
</span>
)
}
return null
}
```
## Error Component
These are the props that will be passed to your custom Error.
| Property | Description |
| --------------- | ------------------------------------------------------------- |
| **`message`** | The error message. |
| **`showError`** | A boolean value that represents if the error should be shown. |
#### Example
```tsx
import React from 'react'
type Props = {
message: string
showError?: boolean
}
const CustomError: React.FC<Props> = (props) => {
const { message, showError } = props
if (showError) {
return <p style={{ color: 'red' }}>{message}</p>
} else return null
}
```
## afterInput and beforeInput
With these properties you can add multiple components before and after the input element. For example, you can add an absolutely positioned button to clear the current field value.
#### Example
```tsx
import React from 'react'
import { Field } from 'payload/types'
import './style.scss'
const ClearButton: React.FC = () => {
return (
<button
onClick={() => {
/* ... */
}}
>
X
</button>
)
}
const titleField: Field = {
name: 'title',
type: 'text',
admin: {
components: {
afterInput: [ClearButton],
},
},
}
export default titleField
```
| **`views`** | Override or create new [Views](./views) within the [Admin Panel](./overview). |
## Custom providers
As your admin customizations gets more complex you may want to share state between fields or other components. You can add custom providers to do add your own context to any Payload app for use in other custom components within the admin panel. Within your config add `admin.components.providers`, these can be used to share context or provide other custom functionality. Read the [React context](https://reactjs.org/docs/context.html) docs to learn more.
As your admin customizations gets more complex you may want to share state between fields or other components. You can add custom providers to do add your own context to any Payload app for use in other custom components within the [Admin Panel](./overview). Within your config add `admin.components.providers`, these can be used to share context or provide other custom functionality. See the [React Context](https://reactjs.org/docs/context.html) docs to learn more.
<Banner type="warning">
<strong>Reminder:</strong> Don't forget to pass the **children** prop through the provider

View File

@@ -1,9 +1,9 @@
---
title: Customizing CSS & SCSS
label: Customizing CSS
order: 40
order: 60
desc: Customize your 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, express
keywords: admin, css, scss, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
## Adding your own CSS / SCSS

View File

@@ -1,206 +0,0 @@
---
title: Excluding server-only code from admin UI
label: Excluding server code
order: 70
desc: Learn how to exclude server-only code from the Payload Admin UI bundle
---
Because the Admin Panel browser bundle includes your Payload Config file, files using server-only modules need to be excluded.
It's common for your config to rely on server only modules to perform logic in access control functions, hooks, and other contexts.
Any file that imports a server-only module such as `fs`, `stripe`, `authorizenet`, `nodemailer`, etc. **cannot** be included in the browser bundle.
## Example Scenario
Say we have a collection called `Subscriptions` that has a `beforeChange` hook that creates a Stripe subscription whenever a Subscription document is created in Payload.
**Collection config**:
```ts
// collections/Subscriptions/index.ts
import { CollectionConfig } from 'payload/types'
import createStripeSubscription from './hooks/createStripeSubscription'
export const Subscription: CollectionConfig = {
slug: 'subscriptions',
hooks: {
beforeChange: [createStripeSubscription],
},
fields: [
{
name: 'stripeSubscriptionID',
type: 'text',
required: true,
},
],
}
```
**Collection hook**:
```ts
// collections/Subscriptions/hooks/createStripeSubscription.ts
// highlight-start
import Stripe from 'stripe' // <-- server-only module
// highlight-end
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY)
export const createStripeSubscription = async ({ data, operation }) => {
if (operation === 'create') {
const dataWithStripeID = { ...data }
// use Stripe to create a Stripe subscription
const subscription = await stripe.subscriptions.create({
// Configure the subscription accordingly
})
// Automatically add the Stripe subscription ID
// to the data that will be saved to this Subscription doc
dataWithStripeID.stripeSubscriptionID = subscription.id
return dataWithStripeID
}
return data
}
```
<Banner type="error">
<strong>Warning:</strong>
<br />
The above code is NOT production-ready and should not be referenced to create Stripe
subscriptions. Although creating a beforeChange hook is a completely valid spot to do things like
create subscriptions, the code above is incomplete and insecure, meant for explanation purposes
only.
</Banner>
**As-is, this collection will prevent your Admin panel from bundling or loading correctly, because Stripe relies on some Node-only packages.**
## How to exclude server-only code
You need to make sure that you use `alias`es to tell your bundler to import "safe" files vs. attempting to import any server-side code that you need to get rid of. Depending on your bundler (Webpack, Vite, etc.) the steps involved may be slightly different.
The basic idea is to create a file that exports an empty object, and then alias import paths of any files that import server-only modules to that empty object file.
This way when your bundler goes to import a file that contains server-only modules, it will instead import the empty object file, which will not break the browser bundle.
### Aliasing server-only modules
To remove files that contain server-only modules from your bundle, you can use an `alias`.
In the Subscriptions config file above, we are importing the hook like so:
```ts
// collections/Subscriptions/index.ts
import createStripeSubscription from './hooks/createStripeSubscription'
```
By default the browser bundle will now include all the code from that file and any files down the tree. We know that the file imports `stripe`.
To fix this, we need to alias the `createStripeSubscription` file to a different file that can safely be included in the browser bundle.
First, we will create a mock file to replace the server-only file when bundling:
```js
// mocks/modules.js
export default {}
/**
* NOTE: if you are destructuring an import
* the mock file will need to export matching
* variables as the destructured object.
*
* export const namedExport = {}
*/
```
Aliasing with [Webpack](/docs/admin/webpack) can be done by:
```ts
// payload.config.ts
import { buildConfig } from 'payload/config'
import { webpackBundler } from '@payloadcms/bundler-webpack'
import { Subscriptions } from './collections/Subscriptions'
const mockModulePath = path.resolve(__dirname, 'mocks/emptyObject.js')
const fullFilePath = path.resolve(
__dirname,
'collections/Subscriptions/hooks/createStripeSubscription',
)
export default buildConfig({
collections: [Subscriptions],
admin: {
bundler: webpackBundler(),
webpack: (config) => {
return {
...config,
resolve: {
...config.resolve,
// highlight-start
alias: {
...config.resolve.alias,
[fullFilePath]: mockModulePath,
},
// highlight-end
},
}
},
},
})
```
Aliasing with [Vite](/docs/admin/vite) can be done by:
```ts
// payload.config.ts
import { buildConfig } from 'payload/config'
import { viteBundler } from '@payloadcms/bundler-vite'
import { Subscriptions } from './collections/Subscriptions'
const mockModulePath = path.resolve(__dirname, 'mocks/emptyObject.js')
export default buildConfig({
collections: [Subscriptions],
admin: {
bundler: viteBundler(),
vite: (incomingViteConfig) => {
const existingAliases = incomingViteConfig?.resolve?.alias || {}
let aliasArray: { find: string | RegExp; replacement: string }[] = []
// Pass the existing Vite aliases
if (Array.isArray(existingAliases)) {
aliasArray = existingAliases
} else {
aliasArray = Object.values(existingAliases)
}
// highlight-start
// Add your own aliases using the find and replacement keys
// remember, vite aliases are exact-match only
aliasArray.push({
find: '../server-only-module',
replacement: path.resolve(__dirname, './path/to/browser-safe-module.js'),
})
// highlight-end
return {
...incomingViteConfig,
resolve: {
...(incomingViteConfig?.resolve || {}),
alias: aliasArray,
},
}
},
},
})
```

194
docs/admin/fields.mdx Normal file
View File

@@ -0,0 +1,194 @@
---
title: Customizing Fields
label: Customizing Fields
order: 40
desc:
keywords:
---
All Payload fields support the ability to swap in your own React components. So, for example, instead of rendering a default Text input, you might need to render a color picker that provides the editor with a custom color picker interface to restrict the data entered to colors only.
<Banner type="success">
<strong>Tip:</strong>
<br />
Don't see a built-in field type that you need? Build it! Using a combination of custom validation
and custom components, you can override the entirety of how a component functions within the admin
panel and effectively create your own field type.
</Banner>
**Fields support the following custom components:**
| Component | Description |
| ------------ | --------------------------------------------------------------------------------------------------------------------------- |
| **`Filter`** | Override the text input that is presented in the `List` view when a user is filtering documents by the customized field. |
| **`Cell`** | Used in the `List` view's table to represent a table-based preview of the data stored in the field. [More](#cell-component) |
| **`Field`** | Swap out the field itself within all `Edit` views. [More](#field-component) |
As an alternative to replacing the entire Field component, you may want to keep the majority of the default Field component and only swap components within. This allows you to replace the **`Label`** or **`Error`** within a field component or add additional components inside the field with **`beforeInput`** or **`afterInput`**. **`beforeInput`** and **`afterInput`** are allowed in any fields that don't contain other fields, except [UI](/docs/fields/ui) and [Rich Text](/docs/fields/rich-text).
| Component | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------- |
| **`Label`** | Override the default Label in the Field Component. [More](#label-component) |
| **`Error`** | Override the default Label in the Field Component. [More](#error-component) |
| **`beforeInput`** | An array of elements that will be added before `input`/`textarea` elements. [More](#afterinput-and-beforeinput) |
| **`afterInput`** | An array of elements that will be added after `input`/`textarea` elements. [More](#afterinput-and-beforeinput) |
## Cell Component
These are the props that will be passed to your custom Cell to use in your own components.
| Property | Description |
| ---------------- | ----------------------------------------------------------------- |
| **`field`** | An object that includes the field configuration. |
| **`colIndex`** | A unique number for the column in the list. |
| **`collection`** | An object with the config of the collection that the field is in. |
| **`cellData`** | The data for the field that the cell represents. |
| **`rowData`** | An object with all the field values for the row. |
#### Example
```tsx
import React from 'react'
import type { Props } from 'payload/components/views/Cell'
import './index.scss'
const baseClass = 'custom-cell'
const CustomCell: React.FC<Props> = (props) => {
const { field, colIndex, collection, cellData, rowData } = props
return <span className={baseClass}>{cellData}</span>
}
```
## Field Component
When writing your own custom components you can make use of a number of hooks to set data, get reactive changes to other fields, get the id of the document or interact with a context from a custom provider.
### Sending and receiving values from the form
When swapping out the `Field` component, you'll be responsible for sending and receiving the field's `value` from the form itself. To do so, import the `useField` hook as follows:
```tsx
import { useField } from 'payload/components/forms'
const CustomTextField: React.FC<{ path: string }> = ({ path }) => {
// highlight-start
const { value, setValue } = useField<string>({ path })
// highlight-end
return <input onChange={(e) => setValue(e.target.value)} value={value} />
}
```
<Banner type="success">
For more information regarding the hooks that are available to you while you build custom
components, including the <strong>useField</strong> hook, [click here](/docs/admin/hooks).
</Banner>
## Label Component
These are the props that will be passed to your custom Label.
| Property | Description |
| -------------- | ---------------------------------------------------------------- |
| **`htmlFor`** | Property used to set `for` attribute for label. |
| **`label`** | Label value provided in field, it can be used with i18n. |
| **`required`** | A boolean value that represents if the field is required or not. |
#### Example
```tsx
import React from 'react'
import { useTranslation } from 'react-i18next'
import { getTranslation } from 'payload/utilities/getTranslation'
type Props = {
htmlFor?: string
label?: Record<string, string> | false | string
required?: boolean
}
const CustomLabel: React.FC<Props> = (props) => {
const { htmlFor, label, required = false } = props
const { i18n } = useTranslation()
if (label) {
return (
<span>
{getTranslation(label, i18n)}
{required && <span className="required">*</span>}
</span>
)
}
return null
}
```
## Error Component
These are the props that will be passed to your custom Error.
| Property | Description |
| --------------- | ------------------------------------------------------------- |
| **`message`** | The error message. |
| **`showError`** | A boolean value that represents if the error should be shown. |
#### Example
```tsx
import React from 'react'
type Props = {
message: string
showError?: boolean
}
const CustomError: React.FC<Props> = (props) => {
const { message, showError } = props
if (showError) {
return <p style={{ color: 'red' }}>{message}</p>
} else return null
}
```
## afterInput and beforeInput
With these properties you can add multiple components before and after the input element. For example, you can add an absolutely positioned button to clear the current field value.
#### Example
```tsx
import React from 'react'
import { Field } from 'payload/types'
import './style.scss'
const ClearButton: React.FC = () => {
return (
<button
onClick={() => {
/* ... */
}}
>
X
</button>
)
}
const titleField: Field = {
name: 'title',
type: 'text',
admin: {
components: {
afterInput: [ClearButton],
},
},
}
export default titleField
```

View File

@@ -1,9 +1,9 @@
---
title: React Hooks
label: React Hooks
order: 30
order: 50
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, express
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload provides a variety of powerful hooks that can be used within your own React components. With them, you can interface with Payload itself and build just about any type of complex customization you can think of—directly in familiar React code.

View File

@@ -3,16 +3,15 @@ title: The Admin Panel
label: Overview
order: 10
desc: Manage your data and customize the Admin Panel by swapping in your own React components. Create, modify or remove views, fields, styles and much more.
keywords: admin, components, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: admin, components, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload dynamically generates a beautiful, fully functional React admin panel to manage your data. It's extremely powerful and can be customized / extended upon easily by swapping in your own React components. You can add additional views, modify how built-in views look / work, swap out Payload branding for your client's, build your own field types and much more.
Payload dynamically generates a beautiful, fully functional Admin Panel to manage your users and data. The Payload Admin Panel is highly performant, even with 100+ fields, and is written fully in TypeScript. It is built with [React](https://react.dev) using the [Next.js App Router](https://nextjs.org/docs/app) and fully supports [React Server Components](https://react.dev/reference/rsc/server-components) which enables the use of the [Local API](/docs/local-api/overview) on the front-end.
The Payload Admin panel can be bundled with our officially supported [Vite](/docs/admin/vite) and [webpack](/docs/admin/webpack) bundlers or you can integrate another bundler following our adapter pattern approach.
When bundled, it is code-split, highly performant (even with 100+ fields), and written fully in TypeScript.
You can endlessly customize and extend the Admin UI by swapping your own in [Custom Components](./components) for everything from field labels to entire views. You can also modify built-in views, build your own fields, [swap out Payload branding for your own](https://payloadcms.com/blog/white-label-admin-ui), and so much more.
<Banner type="success">
The Admin panel is meant to be simple enough to give you a starting point but not bring too much
The Admin Panel is meant to be simple enough to give you a starting point but not bring too much
complexity, so that you can easily customize it to suit the needs of your application and your
editors.
</Banner>
@@ -20,43 +19,36 @@ When bundled, it is code-split, highly performant (even with 100+ fields), and w
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/admin.jpg"
srcDark="https://payloadcms.com/images/docs/admin-dark.jpg"
alt="Admin panel with collapsible sidebar"
caption="Redesigned admin panel with a collapsible sidebar that's open by default, providing greater extensibility and enhanced horizontal real estate."
alt="Admin Panel with collapsible sidebar"
caption="Redesigned Admin Panel with a collapsible sidebar that's open by default, providing greater extensibility and enhanced horizontal real estate."
/>
## Admin Options
All options for the Admin panel are defined in your base Payload config file.
All high-level options for the Admin Panel are defined in your Payload config under the `admin` key:
| Option | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `bundler` | The bundler that you would like to use to bundle the admin panel. Officially supported bundlers: [Webpack](/docs/admin/webpack) and [Vite](/docs/admin/vite). |
| `user` | The `slug` of a Collection that you want be used to log in to the Admin dashboard. [More](/docs/admin/overview#the-admin-user-collection) |
| `buildPath` | Specify an absolute path for where to store the built Admin panel bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
| `meta` | Base meta data 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. |
| `indexHTML` | Optionally replace the entirety of the `index.html` file used by the Admin panel. Reference the [base index.html file](https://github.com/payloadcms/payload/blob/main/packages/payload/src/admin/index.html) to ensure your replacement has the appropriate HTML elements. |
| `css` | Absolute path to a stylesheet that you can use to override / customize the Admin panel styling. [More](/docs/admin/customizing-css). |
| `scss` | Absolute path to a Sass variables / mixins stylesheet meant to override Payload styles to make for an easy re-skinning of the Admin panel. [More](/docs/admin/customizing-css#overriding-scss-variables). |
| `dateFormat` | Global date format that will be used for all dates in the Admin panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
| `user` | The `slug` of a Collection that you want to be used to log in to the Admin Panel. [More](/docs/admin/overview#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 meta data 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` | Global date format that will be used for all dates in 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](/docs/authentication/config). |
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More](/docs/live-preview/overview). |
| `components` | Component overrides that affect the entirety of the Admin panel. [More](/docs/admin/components) |
| `webpack` | Customize the Webpack config that's used to generate the Admin panel. [More](/docs/admin/webpack) |
| `vite` | Customize the Vite config that's used to generate the Admin panel. [More](/docs/admin/vite) |
| `routes` | Replace built-in Admin Panel routes with your own custom routes. I.e. `{ logout: '/custom-logout', inactivity: 'custom-inactivity' }` |
| `components` | Component overrides that affect the entirety of the Admin Panel. [More](/docs/admin/components) |
| `routes` | Replace built-in Admin Panel routes with your own custom routes. [More](#custom-admin-panel-routes) |
### The Admin User Collection
<Banner type="warning">
<strong>Important:</strong>
<br />
The Payload Admin panel can only be used by one Collection that supports
[Authentication](/docs/authentication/overview).
The Admin Panel can only be used by a single auth-enabled Collection. To enable authentication for a Collection, simply set `auth: true` in the Collection's configuration. See [Authentication](/docs/authentication/overview) for more information.
</Banner>
To specify which Collection to use to log in to the Admin panel, pass the `admin` options a `user` key equal to the slug of the Collection that you'd like to use.
To specify which Collection to allow to login to the Admin Panel, pass the `admin.user` key equal to the slug of any auth-enabled Collection. See [Authentication](/docs/authentication/overview) for more information.
`payload.config.js`:
@@ -70,21 +62,67 @@ const config = buildConfig({
})
```
By default, if you have not specified a Collection, Payload will automatically provide you with a `User` Collection which will be used to access the Admin panel. You can customize or override the fields and settings of the default `User` Collection by passing your own collection using `users` as its `slug` to Payload. When this is done, Payload will use your provided `User` Collection instead of its default version.
<Banner type="info">
By default, if you have not specified a Collection, Payload will automatically provide a `User` Collection with access the Admin Panel. You can customize or override the fields and settings of the default `User` Collection by adding your own Collection with `slug: 'users'`. Doing this will force Payload to use your provided `User` Collection instead of its default version.
</Banner>
**Note: you can use whatever Collection you'd like to access the Admin panel as long as the Collection supports Authentication. It doesn't need to be called `users`!**
<Banner type="warning">
<strong>Note:</strong>
<br />
You can use whatever Collection you'd like to access the Admin Panel as long as the Collection supports [Authentication](/docs/authentication/overview). It doesn't need to be called `users`. For example, you could use a Collection called `admins` or `editors` instead.
</Banner>
For example, you may wish to have two Collections that both support `Authentication`:
For example, you may wish to have two Collections that both support Authentication:
- `admins` - meant to have a higher level of permissions to manage your data and access the Admin panel
- `customers` - meant for end users of your app that should not be allowed to log into the Admin panel
- `admins` - meant to have a higher level of permissions to manage your data and access the Admin Panel
- `customers` - meant for end users of your app that should not be allowed to log into the Admin Panel
This is totally possible. For the above scenario, by specifying `admin: { user: 'admins' }`, your Payload Admin panel will use `admins`. Any users logged in as `customers` will not be able to log in via the Admin panel.
### Light and dark modes
Users in the admin panel have access to choosing between light mode and dark mode for their editing experience. The setting is managed while logged into the admin UI within the user account page and will be stored with the browser. By default, the operating system preference is detected and used.
This is totally possible. For the above scenario, by specifying `admin: { user: 'admins' }`, your Admin Panel will use `admins`. Any users logged in as `customers` will not be able to log in via the Admin Panel.
### Restricting user access
If you would like to restrict which users from a single Collection can access the Admin panel, you can use the `admin` access control function. [Click here](/docs/access-control/overview#admin) to learn more.
It is also possible to allow _multiple admin user types_ into the Admin Panel with limited permissions. To do this, add a `roles` or similar field to your auth-enabled Collection and use the `access.admin` property to limit access. See [Access Control](/docs/access-control/overview) for full details. For a working example, check out the [Auth Example](https://github.com/payloadcms/payload/tree/main/examples/auth/payload).
### I18n
The Payload Admin Panel is translated in over 30 languages and counting. Languages are automatically detected based on the user's browser and all text displays in that language. If no language was detected, or if the user's language is not yet supported, English will be chosen. Users can easily specify their language by selecting one from their account page. See [I18n](../configuration/i18n) for more information.
<Banner>
<strong>Note:</strong>
<br />
If there is a language that Payload does not yet support, we accept code
[contributions](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md).
</Banner>
### Light and dark modes
Users in the Admin Panel have access to choosing between light mode and dark mode for their editing experience. The setting is managed while logged into the admin UI within the user account page and will be stored with the browser. By default, the operating system preference is detected and used.
### Custom admin panel routes
You can configure custom routes in the Admin Panel for the following routes:
| Option | Default route |
| ----------------- | ----------------------- |
| `account` | `/account` |
| `createFirstUser` | `/create-first-user` |
| `forgot` | `/forgot` |
| `inactivity` | `/logout-inactivity` |
| `login` | `/login` |
| `logout` | `/logout` |
| `reset` | `/reset` |
| `unauthorized` | `/unauthorized` |
`payload.config.js`:
```ts
import { buildConfig } from 'payload/config'
const config = buildConfig({
admin: {
routes: {
admin: '/custom-admin-route'
}
},
})
```

View File

@@ -3,7 +3,7 @@ title: Managing User Preferences
label: Preferences
order: 50
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, express
keywords: admin, preferences, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
As your users interact with your Admin panel, you might want to store their preferences in a persistent manner, so that when they revisit the Admin panel, they can pick right back up where they left off.

315
docs/admin/views.mdx Normal file
View File

@@ -0,0 +1,315 @@
---
title: Customizing Views
label: Customizing Views
order: 30
desc:
keywords:
---
### Root
You can easily swap entire views with your own by using the `admin.components.views` property. At the root level, Payload renders the following views by default, all of which can be overridden:
| Property | Description |
| --------------- | ----------------------------------------------------------------------------- |
| **`Account`** | The Account view is used to show the currently logged in user's Account page. |
| **`Dashboard`** | The main landing page of the [Admin Panel](./overview). |
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. For example:
```ts
// payload.config.ts
{
// ...
admin: {
components: {
views: {
Account: MyCustomAccountView,
Dashboard: MyCustomDashboardView,
},
},
},
}
```
For more granular control, pass a configuration object instead. Payload exposes the following properties for each view:
| Property | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`Component`** \* | Pass in the component that should be rendered when a user navigates to this route. |
| **`path`** \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
| **`exact`** | Boolean. When true, will only match if the path matches the `usePathname()` exactly. |
| **`strict`** | When true, a path that has a trailing slash will only match a location.pathname with a trailing slash. This has no effect when there are additional URL segments in the location.pathname. |
| **`sensitive`** | When true, will match if the path is case sensitive. |
_\* An asterisk denotes that a property is required._
#### Adding new root views
To add a _new_ view to the [Admin Panel](./overview), simply add another key to the `views` object with at least a `path` and `Component` property. For example:
```ts
// payload.config.ts
{
// ...
admin: {
components: {
views: {
MyCustomView: {
Component: MyCustomView,
path: '/my-custom-view',
},
},
},
},
}
```
<Banner type="warning">
<strong>Note:</strong>
<br />
Routes are cascading. This means that unless explicitly given the `exact` property, they will
match on URLs that simply _start_ with the route's path. This is helpful when creating catch-all
routes in your application. Alternatively, you could define your nested route _before_ your parent
route.
</Banner>
For help on how to build your own custom view components, see [Building Custom View Components](#building-custom-view-components). For more examples regarding how to customize components, [look at the following examples](https://github.com/payloadcms/payload/tree/main/test/admin/components)._
### Collections
To swap out entire views on collections, you can use the `admin.components.views` property on the collection's config. Payload renders the following views by default, all of which can be overridden:
| Property | Description |
| ---------- | ------------------------------------------------------------------------- |
| **`Edit`** | The Edit view is used to edit a single document for a given collection. |
| **`List`** | The List view is used to show a list of documents for a given collection. |
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, tabs, etc, _as well as all nested routes_.
```ts
// Collection.ts
{
// ...
admin: {
components: {
views: {
Edit: MyCustomEditView,
List: MyCustomListView,
},
},
},
}
```
For help on how to build your own custom view components, see [Building Custom View Components](#building-custom-view-components).
**Customizing Nested Views within 'Edit' in Collections**
The `Edit` view in collections consists of several nested views, each serving a unique purpose. You can customize these nested views using the `admin.components.views.Edit` property in the collection's configuration. This approach allows you to replace specific nested views while keeping the overall structure of the `Edit` view intact, including the page breadcrumbs, title, tabs, etc.
Here's an example of how you can customize nested views within the `Edit` view in collections, including the use of the `actions` property:
```ts
// Collection.ts
{
// ...
admin: {
components: {
views: {
Edit: {
Default: {
Component: MyCustomDefaultTab,
actions: [CollectionEditButton], // Custom actions for the default edit view
},
API: {
Component: MyCustomAPIView,
actions: [CollectionAPIButton], // Custom actions for API view
},
LivePreview: {
Component: MyCustomLivePreviewView,
actions: [CollectionLivePreviewButton], // Custom actions for Live Preview
},
Version: {
Component: MyCustomVersionView,
actions: [CollectionVersionButton], // Custom actions for Version view
},
Versions: {
Component: MyCustomVersionsView,
actions: [CollectionVersionsButton], // Custom actions for Versions view
},
},
List: {
actions: [CollectionListButton],
},
},
},
},
}
```
**Adding New Tabs to 'Edit' View**
You can also add _new_ tabs to the `Edit` view by adding another key to the `components.views.Edit[key]` object with a `path` and `Component` property. See [Custom Tabs](#custom-tabs) for more information.
### Globals
To swap out views for globals, you can use the `admin.components.views` property on the global's config. Payload renders the following views by default, all of which can be overridden:
| Property | Description |
| ---------- | ------------------------------------------------------------------- |
| **`Edit`** | The Edit view is used to edit a single document for a given Global. |
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, and tabs, _as well as all nested views_.
```ts
// Global.ts
{
// ...
admin: {
components: {
views: {
Edit: MyCustomEditView,
},
},
},
}
```
For help on how to build your own custom view components, see [Building Custom View Components](#building-custom-view-components).
**Customizing Nested Views within 'Edit' in Globals**
Similar to collections, Globals allow for detailed customization within the `Edit` view. This includes the ability to swap specific nested views while maintaining the overall structure of the `Edit` view. You can use the `admin.components.views.Edit` property in the Globals configuration to achieve this, and this will only replace the nested view, leaving the page breadcrumbs, title, and tabs intact.
Here's how you can customize nested views within the `Edit` view in Globals, including the use of the `actions` property:
```ts
// Global.ts
{
// ...
admin: {
components: {
views: {
Edit: {
Default: {
Component: MyCustomGlobalDefaultTab,
actions: [GlobalEditButton], // Custom actions for the default edit view
},
API: {
Component: MyCustomGlobalAPIView,
actions: [GlobalAPIButton], // Custom actions for API view
},
LivePreview: {
Component: MyCustomGlobalLivePreviewView,
actions: [GlobalLivePreviewButton], // Custom actions for Live Preview
},
Version: {
Component: MyCustomGlobalVersionView,
actions: [GlobalVersionButton], // Custom actions for Version view
},
Versions: {
Component: MyCustomGlobalVersionsView,
actions: [GlobalVersionsButton], // Custom actions for Versions view
},
},
},
},
},
}
```
You can also add _new_ tabs to the `Edit` view by adding another key to the `components.views.Edit[key]` object with a `path` and `Component` property. See [Custom Tabs](#custom-tabs) for more information.
### Custom Tabs
You can easily swap individual collection or global edit views. To do this, pass an _object_ to the `admin.components.views.Edit` property of the config. Payload renders the following views by default, all of which can be overridden:
| Property | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------- |
| **`Default`** | The Default view is the primary view in which your document is edited. |
| **`Versions`** | The Versions view is used to view the version history of a single document. [More details](../versions) |
| **`Version`** | The Version view is used to view a single version of a single document for a given collection. [More details](../versions). |
| **`API`** | The API view is used to display the REST API JSON response for a given document. |
| **`LivePreview`** | The LivePreview view is used to display the Live Preview interface. [More details](../live-preview) |
Here is an example:
```ts
// Collection.ts or Global.ts
export const MyCollection: SanitizedCollectionConfig = {
slug: 'my-collection',
admin: {
components: {
views: {
Edit: {
// You can also define `components.views.Edit` as a component, this will override _all_ nested views
Default: MyCustomDefaultTab,
Versions: MyCustomVersionsTab,
Version: MyCustomVersionTab,
API: MyCustomAPITab,
LivePreview: MyCustomLivePreviewTab,
},
},
},
},
}
```
To add a _new_ tab to the `Edit` view, simply add another key to `components.views.Edit[key]` with at least a `path` and `Component` property. For example:
```ts
// `Collection.ts` or `Global.ts`
export const MyCollection: SanitizedCollectionConfig = {
slug: 'my-collection',
admin: {
components: {
views: {
Edit: {
MyCustomTab: {
Component: MyCustomTab,
path: '/my-custom-tab',
// You an swap the entire tab component out for your own
Tab: MyCustomTab,
},
AnotherCustomView: {
Component: AnotherCustomView,
path: '/another-custom-view',
// Or you can use the default tab component and just pass in your own label and href
Tab: {
label: 'Another Custom View',
href: '/another-custom-view',
},
},
},
},
},
},
}
```
### Building Custom View Components
Your custom view components will be provided with the following props:
| Prop | Description |
| ----------------------- | ---------------------------------------------------------------------------- |
| **`user`** | The currently logged in user. Will be `null` if no user is logged in. |
| **`canAccessAdmin`** \* | If the currently logged in user is allowed to access the [Admin Panel](./overview) or not. |
<Banner type="warning">
<strong>Note:</strong>
<br />
It's up to you to secure your custom views. If your view requires a user to be logged in or to
have certain access rights, you should handle that within your view component yourself.
</Banner>
### Examples
You can find examples of custom views in the [Payload source code `/test/admin/components/views` folder](https://github.com/payloadcms/payload/tree/main/test/admin/components/views). There, you'll find two custom views:
1. A custom view that uses the `DefaultTemplate`, which is the built-in Payload template that displays the sidebar and "eyebrow nav"
1. A custom view that uses the `MinimalTemplate` - which is just a centered template used for things like logging in or out
To see how to pass in your custom views to create custom views of your own, take a look at the `admin.components.views` property of the [Payload test admin config](https://github.com/payloadcms/payload/blob/main/test/admin/config.ts).

View File

@@ -1,163 +0,0 @@
---
title: Vite
label: Vite
order: 90
desc: NEEDS TO BE WRITTEN
---
<Banner type="info">
The Vite bundler is currently in beta. If you would like to help us test this package, we'd love
to hear from you if you find any [bugs or issues](https://github.com/payloadcms/payload/issues/)!
</Banner>
Payload has a Vite bundler that you can install and bundle the Admin Panel with. This is an alternative to the [Webpack](/docs/admin/webpack) bundler and might give some performance boosts to your development workflow.
To use Vite as your bundler, first you need to install the package:
```bash
yarn add @payloadcms/bundler-vite
```
Then you will need to add the [bundler](/docs/admin/bundlers) to your Payload config:
```ts
import { buildConfig } from '@payloadcms/config'
import { viteBundler } from '@payloadcms/bundler-vite'
export default buildConfig({
collections: [],
admin: {
bundler: viteBundler(),
},
})
```
Vite works fundamentally differently than Webpack. In development mode, it will first pre-bundle any of your dependencies that are CommonJS-only, and then it'll leverage ESM directly in your browser for a better HMR experience.
It then uses Rollup to create production builds of your admin UI. With Vite, you should see a decent performance boost—especially after your first cold start. However, that first cold start might take a few more seconds.
<Banner type="warning">
In most cases, Vite should work out of the box. But existing Payload plugins may need to make
compatibility changes to support Vite.
</Banner>
This is because Vite aliases work fundamentally differently than Webpack aliases, and Payload relies on aliasing server-only code out of the Payload config to ensure that the bundled admin JS works within your browser.
Here are the main differences between how Vite aliases work and how Webpack aliases work.
**Vite aliases do not work with absolute paths.**
In Vite, alias keys must <strong>exactly match</strong> a import paths. If you have 2 files that import the same server-only module, but have different import paths, you would need to add 2 aliases to support both import paths.
```ts
// File A
import serverOnlyModule from '../server-only-module'
// File B
import serverOnlyModule from '../../server-only-module'
// payload.config.ts
// You would need to add 2 aliases to support both import paths
export const buildConfig({
collections: [],
admin: {
bundler: viteBundler(),
vite: (incomingViteConfig) => {
const existingAliases = incomingViteConfig?.resolve?.alias || {};
let aliasArray: { find: string | RegExp; replacement: string; }[] = [];
// Pass the existing Vite aliases
if (Array.isArray(existingAliases)) {
aliasArray = existingAliases;
} else {
aliasArray = Object.values(existingAliases);
}
// Add your own aliases using the find and replacement keys
aliasArray.push({
find: '../server-only-module',
replacement: path.resolve(__dirname, './path/to/browser-safe-module.js')
find: '../../server-only-module',
replacement: path.resolve(__dirname, './path/to/browser-safe-module.js')
});
return {
...incomingViteConfig,
resolve: {
...(incomingViteConfig?.resolve || {}),
alias: aliasArray,
}
};
},
}
})
```
**Vite aliases do not get applied to pre-bundled dependencies.**
This especially affects plugins, as plugins will be pre-bundled by Vite using `esbuild`. To get around this and support Vite, plugin authors need to configure an alias to their plugin at the top level, so that the alias will work accordingly.
Here's an example. Say your plugin is called `payload-plugin-cool`. It's imported as follows:
```ts
import { myCoolPlugin } from 'payload-plugin-cool'
```
That plugin should create an alias to support Vite as follows:
```ts
{
// aliases go here
find: 'payload-plugin-cool',
replacement: path.resolve(__dirname, './my-admin-plugin.js')
}
```
This will effectively alias the entire plugin and work with Vite. If the plugin requires admin-specific code, then the `./my-admin-plugin.js` alias target file should reflect any changes necessary to the admin UI that the main server-side plugin performs.
## Extending the Vite config
The Payload config supports a new property for plugins to be able to extend the Vite config specifically. That property exists on the main Payload config under `admin.vite`. You can check out the [Vite docs](https://vitejs.dev/config/shared-options.html) for more information on what you can do with the Vite config.
It's a function that takes a Vite config, and returns an updated Vite config. Here's an example:
```ts
export const buildConfig({
collections: [],
admin: {
bundler: viteBundler(),
vite: (incomingViteConfig) => {
const existingAliases = incomingViteConfig?.resolve?.alias || {};
let aliasArray: { find: string | RegExp; replacement: string; }[] = [];
// Pass the existing Vite aliases
if (Array.isArray(existingAliases)) {
aliasArray = existingAliases;
} else {
aliasArray = Object.values(existingAliases);
}
// Add your own aliases using the find and replacement keys
aliasArray.push({
find: '../server-only-module',
replacement: path.resolve(__dirname, './path/to/browser-safe-module.js')
});
return {
...incomingViteConfig,
resolve: {
...(incomingViteConfig?.resolve || {}),
alias: aliasArray,
}
};
},
}
})
```
Learn more about [aliasing server-only modules](https://payloadcms.com/docs/admin/excluding-server-code#aliasing-server-only-modules).
Even though there is a new property for Vite configs specifically, we have implemented some "compatibility" between Webpack and Vite out-of-the-box.
If your config specifies Webpack aliases, we attempt to leverage them automatically within the Vite config. They are merged into the Vite alias configuration seamlessly and may work out-of-the-box.

View File

@@ -1,67 +0,0 @@
---
title: Webpack
label: Webpack
order: 80
desc: The Payload admin panel uses Webpack 5 and supports many common functionalities such as SCSS and Typescript out of the box to give you more freedom.
keywords: admin, webpack, documentation, Content Management System, cms, headless, javascript, node, react, express
---
Payload has a Webpack (v5) bundler that you can build the Admin panel with. For now, we recommended using it because it is stable. If you are feeling a bit more adventurous you can give the [Vite](/docs/admin/vite) bundler a shot.
Out of the box, the Webpack bundler supports common functionalities such as SCSS and Typescript, but there are many cases where you may need to add support for additional functionalities.
## Installation
```bash
yarn add @payloadcms/bundler-webpack
```
### Import the bundler
```ts
// payload.config.ts
import { buildConfig } from 'payload/config'
import { webpackBundler } from '@payloadcms/bundler-webpack'
export default buildConfig({
// highlight-start
admin: {
bundler: webpackBundler(),
},
// highlight-end
})
```
## Extending Webpack
If you need to extend the Webpack config, you can do so by passing a function to the `admin.webpack` property on your Payload config.
The function will receive the Webpack config as an argument and should return the modified config.
```ts
// payload.config.ts
import { buildConfig } from 'payload/config'
import { webpackBundler } from '@payloadcms/bundler-webpack'
export default buildConfig({
admin: {
bundler: webpackBundler()
// highlight-start
webpack: (config) => {
// full control of the Webpack config
return config
},
// highlight-end
},
})
```
<Banner type="success">
<strong>Tip:</strong>
<br />
If changes to your Webpack aliases are not surfacing, they might be
[cached](https://webpack.js.org/configuration/cache/) in `node_modules/.cache/webpack`. Try
deleting that folder and restarting your server.
</Banner>

View File

@@ -3,7 +3,7 @@ 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, express
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.
@@ -18,7 +18,7 @@ To enable Authentication on a collection, define an `auth` property and set it t
| **`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 express `req`. Defaults to `0` and should only be modified if absolutely necessary, as this will affect performance. |
| **`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) |

View File

@@ -3,7 +3,7 @@ title: Authentication Operations
label: Operations
order: 30
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, express
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.
@@ -107,7 +107,7 @@ query {
## Login
Accepts an `email` and `password`. On success, it will return the logged in user as well as a token that can be used to authenticate. In the GraphQL and REST APIs, this operation also automatically sets an HTTP-only cookie including the user's token. If you pass an Express `res` to the Local API operation, Payload will set a cookie there as well.
Accepts an `email` and `password`. On success, it will return the logged in user as well as a token that can be used to authenticate. In the GraphQL and REST APIs, this operation also automatically sets an HTTP-only cookie including the user's token. If you pass a `res` to the Local API operation, Payload will set a cookie there as well.
**Example REST API login**:

View File

@@ -3,7 +3,7 @@ title: Authentication Overview
label: Overview
order: 10
desc: Payload provides highly secure user Authentication out of the box, and you can fully customize, override, or remove the default Authentication support.
keywords: authentication, config, configuration, overview, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: authentication, config, configuration, overview, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<YouTube
@@ -77,14 +77,14 @@ Once enabled, each document that is created within the Collection can be thought
## Token-based auth
Successfully logging in returns a `JWT` (JSON web token) which is how a user will identify themselves to Payload. By providing this JWT via either an HTTP-only cookie or an `Authorization: JWT` or `Authorization: Bearer` header, Payload will automatically identify the user and add its user JWT data to the Express `req`, which is available throughout Payload including within access control, hooks, and more.
Successfully logging in returns a `JWT` (JSON web token) which is how a user will identify themselves to Payload. By providing this JWT via either an HTTP-only cookie or an `Authorization: JWT` or `Authorization: Bearer` header, Payload will automatically identify the user and add its user JWT data to the `req`, which is available throughout Payload including within access control, hooks, and more.
You can specify what data gets encoded to the JWT token by setting `saveToJWT` to true in your auth collection fields. If you wish to use a different key other than the field `name`, you can provide it to `saveToJWT` as a string. It is also possible to use `saveToJWT` on fields that are nested in inside groups and tabs. If a group has a `saveToJWT` set it will include the object with all sub-fields in the token. You can set `saveToJWT: false` for any fields you wish to omit. If a field inside a group has `saveToJWT` set, but the group does not, the field will be included at the top level of the token.
<Banner type="success">
<strong>Tip:</strong>
<br />
You can access the logged-in user from access control functions and hooks via the Express{' '}
You can access the logged-in user from access control functions and hooks via the{' '}
<strong>req</strong>. The logged-in user is automatically added as the <strong>user</strong>{' '}
property.
</Banner>

View File

@@ -1,56 +0,0 @@
---
title: Using the Payload Auth Middleware
label: Using the Middleware
order: 40
desc: Make full use of Payload's built-in authentication with your own custom Express endpoints by adding Payload's authentication middleware.
keywords: authentication, middleware, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
---
Because Payload uses your existing Express server, you are free to add whatever logic you need to your app through endpoints of your own. However, Payload does not add its middleware to your Express app itself—instead, it scopes all of its middleware to Payload-specific routers.
This approach has a ton of benefits - it's great for isolation of concerns and limiting scope, but it also means that your additional routes won't have access to Payload's user authentication.
<Banner type="success">
You can make full use of Payload's built-in authentication within your own custom Express
endpoints by adding Payload's authentication middleware.
</Banner>
<Banner type="warning">
Payload must be initialized before the `payload.authenticate` middleware can be used. This is done
by calling `payload.init()` prior to adding the middleware.
</Banner>
Example in `server.js`:
```ts
import express from 'express'
import payload from 'payload'
const app = express()
const start = async () => {
await payload.init({
secret: 'PAYLOAD_SECRET_KEY',
express: app,
})
const router = express.Router()
// Note: Payload must be initialized before the `payload.authenticate` middleware can be used
router.use(payload.authenticate) // highlight-line
router.get('/', (req, res) => {
if (req.user) {
return res.send(`Authenticated successfully as ${req.user.email}.`)
}
return res.send('Not authenticated')
})
app.use('/some-route-here', router)
app.listen(3000)
}
start()
```

View File

@@ -46,7 +46,7 @@ Any of the features in Payload Cloud that require environment variables will aut
<Banner type="warning">
Note: For security reasons, any variables you wish to provide to the Admin panel must be prefixed
with `PAYLOAD_PUBLIC_`.  Learn more
[here](https://payloadcms.com/docs/admin/webpack#admin-environment-vars).
[here](https://payloadcms.com/docs/admin/environment-vars).
</Banner>
## Payment

View File

@@ -61,7 +61,7 @@ From the Environment Variables page of the Settings tab, you can add, update and
<Banner>
Note: For security reasons, any variables you wish to provide to the Admin panel must be prefixed
with `PAYLOAD_PUBLIC_`.  Learn more
[here](https://payloadcms.com/docs/admin/webpack#admin-environment-vars).
[here](https://payloadcms.com/docs/admin/environment-vars).
</Banner>
## Custom Domains

View File

@@ -3,7 +3,7 @@ title: Collection Configs
label: Collections
order: 20
desc: Structure your Collections for your needs by defining fields, adding slugs and labels, establishing access control, tying in hooks, setting timestamps and more.
keywords: collections, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: collections, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload Collections are defined through configs of their own, and you can define as many as your application needs. Each

View File

@@ -1,81 +0,0 @@
---
title: Express
label: Express
order: 60
desc: Payload utilizes Express middleware packages, you can customize how they work by passing in configuration options.
keywords: config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
---
Payload utilizes a few Express-specific middleware packages within its own routers. You can customize how they work by passing in configuration options to the main Payload config's `express` property.
## Custom Middleware
Payload allows you to pass in custom Express middleware to be used on all of the routes it opens. This is useful for adding logging or any other custom functionality to your endpoints.
There are 2 exposed properties. Each property is an array of middleware functions.
- `preMiddleware` - runs before any of the Payload middleware
- `postMiddleware` - runs after all of the Payload middleware
```ts
{
express: {
preMiddleware: [
(req, res, next) => {
// do something
next()
}
],
postMiddleware: [
(req, res, next) => {
// do something
next()
}
]
}
}
// Example logging middleware function
const requestLoggerMiddleware = (req, res, next) => {
req.payload.logger.info(`request: ${req.method} ${req.url}`)
next()
}
```
## JSON
`express.json()` is used to parse JSON body content into JavaScript objects accessible on the Express `req`. Payload allows you to customize all of the `json` method's options. Common examples of customization use-cases are increasing the max allowed JSON body size which defaults to `2MB`.
**Example payload.config.js for how to increase the max JSON size allowed to be sent to Payload endpoints:**
```js
{
express: {
json: {
limit: '4mb',
}
}
}
```
You can find a list of all available options that are able to be passed to `express.json()` [here](https://expressjs.com/en/api.html).
## Compression
Payload uses the `compression` package to optimize transfer size for all of the routes it opens, and you can pass customization options through the Payload config.
To customize compression options, pass an object to the Payload config's `express` property.
**Example payload.config.js:**
```js
{
express: {
compression: {
// settings go here
}
}
}
```
Typically, the default options for this package are suitable. However, for a list of all available customization options, [click here](http://expressjs.com/en/resources/middleware/compression.html).

View File

@@ -3,7 +3,7 @@ title: Global Configs
label: Globals
order: 30
desc: Set up your Global config for your needs by defining fields, adding slugs and labels, establishing access control, tying in hooks and more.
keywords: globals, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: globals, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Global configs are in many ways similar to [Collections](/docs/configuration/collections). The big difference is that Collections will potentially contain _many_ documents, while a Global is a "one-off". Globals are perfect for things like header nav, site-wide banner alerts, app-wide localized strings, and other "global" data that your site or app might rely on.

View File

@@ -3,12 +3,43 @@ title: I18n
label: I18n
order: 40
desc: Manage and customize internationalization support in your CMS editor experience
keywords: internationalization, i18n, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: internationalization, i18n, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Not only does Payload support managing localized content, it also has internationalization support so that admin users can work in their preferred language. It comes included by default and can be extended in your config.
Not only does Payload support managing localized content, it also has internationalization support so that users in the [Admin Panel](../admin/overview) can work in their preferred language. Payload's i18n comes by default without any additional setup, and you can extend the default settings to customize the language settings to your needs.
While Payload's built-in features come translated, you may want to also translate parts of your project's configuration too. This is possible in places like collections and globals labels and groups, field labels, descriptions and input placeholder text. The admin UI will display all the correct translations you provide based on the user's language.
### Configuration Options
In your Payload config, you can add translations and customize the settings in `i18n`. Payload will use your custom options and merge it with the default, allowing you to override the settings Payload provides.
**Example Payload config extending i18n:**
```ts
import { buildConfig } from 'payload/config'
export default buildConfig({
//...
i18n: {
fallbackLng: 'en', // default
debug: false, // default
resources: {
en: {
custom: {
// namespace can be anything you want
key1: 'Translation with {{variable}}', // translation
},
// override existing translation keys
general: {
dashboard: 'Home',
},
},
},
},
//...
})
```
While Payload's built-in features come translated, you may want to also translate parts of your project's configuration too. This is possible in places like Collections and Globals labels and groups, field labels, descriptions and input placeholder text. The admin UI will display all the correct translations you provide based on the user's language.
Here is an example of a simple collection supporting both English and Spanish editors:
@@ -58,7 +89,7 @@ export const Articles: CollectionConfig = {
## Admin UI
The Payload admin panel reads the language settings of a user's browser and display all text in that language, or will fall back to English if the user's language is not yet supported.
The [Admin Panel](../admin/overview) reads the language settings of a user's browser and display all text in that language, or will fall back to English if the user's language is not yet supported.
After a user logs in, they can change their language selection in the `/account` view.
<Banner>
@@ -68,9 +99,9 @@ After a user logs in, they can change their language selection in the `/account`
[contributions](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md).
</Banner>
## Node Express
## Node
Payload's backend uses express middleware to set the language on incoming requests before they are handled. This allows backend validation to return error messages in the user's own language or system generated emails to be sent using the correct translation. You can make HTTP requests with the `accept-language` header and Payload will use that language.
Payload's backend sets the language on incoming requests before they are handled. This allows backend validation to return error messages in the user's own language or system generated emails to be sent using the correct translation. You can make HTTP requests with the `accept-language` header and Payload will use that language.
Anywhere in your Payload app that you have access to the `req` object, you can access payload's extensive internationalization features assigned to `req.i18n`. To access text translations you can use `req.t('namespace:key')`.

View File

@@ -3,7 +3,7 @@ title: Localization
label: Localization
order: 50
desc: Add and maintain as many locales as you need by adding Localization to your Payload config, set options for default locale, fallbacks, fields and more.
keywords: localization, internationalization, i18n, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: localization, internationalization, i18n, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload features deep field-based localization support. Maintaining as many locales as you need is easy. All

View File

@@ -3,7 +3,7 @@ title: The Payload Config
label: Overview
order: 10
desc: The Payload config is central to everything that Payload does, from adding custom React components, to modifying collections, controlling localization and much more.
keywords: overview, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: overview, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload is a _config-based_, code-first CMS and application framework. The Payload config is central to everything that Payload does. It scaffolds the data that Payload stores as well as maintains custom React components, hook logic, custom validations, and much more.
@@ -13,7 +13,7 @@ Payload is a _config-based_, code-first CMS and application framework. The Paylo
<Banner type="warning">
<strong>Important:</strong>
<br />
This file is included in the Payload admin bundle, so make sure you do not embed any sensitive
The serializable portions of this config are included in the Payload Admin bundle, so make sure you do not embed any sensitive
information.
</Banner>
@@ -21,7 +21,7 @@ Payload is a _config-based_, code-first CMS and application framework. The Paylo
| Option | Description |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `admin` \* | Base Payload admin configuration. Specify bundler\*, custom components, control metadata, set the Admin user collection, and [more](/docs/admin/overview#admin-options). Required. |
| `admin` \* | Base Payload admin configuration. Specify, custom components, control metadata, set the Admin user collection, and [more](/docs/admin/overview#admin-options). Required. |
| `editor` \* | Rich Text Editor which will be used by richText fields. Required. |
| `db` \* | Database Adapter which will be used by Payload. Read more [here](/docs/database/overview). Required. |
| `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 |
@@ -38,7 +38,6 @@ Payload is a _config-based_, code-first CMS and application framework. The Paylo
| `upload` | Base Payload upload configuration. [More](/docs/upload/overview#payload-wide-upload-options). |
| `routes` | Control the routing structure that Payload binds itself to. Specify `admin`, `api`, `graphQL`, and `graphQLPlayground`. |
| `email` | Base email settings to allow Payload to generate email such as Forgot Password requests and other requirements. [More](/docs/email/overview#configuration) |
| `express` | Express-specific middleware options such as compression and JSON parsing. [More](/docs/configuration/express) |
| `debug` | Enable to expose more detailed error information. |
| `telemetry` | Disable Payload telemetry by passing `false`. [More](/docs/configuration/overview#telemetry) |
| `rateLimit` | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks and [more](/docs/production/preventing-abuse#rate-limiting-requests). |
@@ -56,16 +55,10 @@ import { buildConfig } from 'payload/config'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { postgresAdapter } from '@payloadcms/db-postgres' // beta
import { viteBundler } from '@payloadcms/bundler-vite'
import { webpackBundler } from '@payloadcms/bundler-webpack'
import { lexicalEditor } from '@payloadcms/richtext-lexical' // beta
import { slateEditor } from '@payloadcms/richtext-slate'
export default buildConfig({
admin: {
bundler: webpackBundler(), // or viteBundler()
},
db: mongooseAdapter({}) // or postgresAdapter({}),
editor: lexicalEditor({}) // or slateEditor({})
collections: [
@@ -139,7 +132,7 @@ project-name
<br />
If you use an environment variable to configure any properties that are required for the Admin
panel to function (ex. serverURL or any routes), you need to make sure that your Admin panel code
can access it. [Click here](/docs/admin/webpack#admin-environment-vars) for more info.
can access it. [Click here](/docs/admin/environment-vars) for more info.
</Banner>
## Customizing & Automating Config Location Detection

View File

@@ -2,7 +2,7 @@
title: Migrations
label: Migrations
order: 20
keywords: database, migrations, ddl, sql, mongodb, postgres, documentation, Content Management System, cms, headless, typescript, node, react, express
keywords: database, migrations, ddl, sql, mongodb, postgres, documentation, Content Management System, cms, headless, typescript, node, react, nextjs
desc: Payload features first-party database migrations all done in TypeScript.
---

View File

@@ -3,7 +3,7 @@ title: MongoDB
label: MongoDB
order: 40
desc: Payload has supported MongoDB natively since we started. The flexible nature of MongoDB lends itself well to Payload's powerful fields.
keywords: MongoDB, documentation, typescript, Content Management System, cms, headless, javascript, node, react, express
keywords: MongoDB, documentation, typescript, Content Management System, cms, headless, javascript, node, react, nextjs
---
To use Payload with MongoDB, install the package `@payloadcms/db-mongodb`. It will come with everything you need to

View File

@@ -2,7 +2,7 @@
title: Database
label: Overview
order: 10
keywords: database, mongodb, postgres, documentation, Content Management System, cms, headless, typescript, node, react, express
keywords: database, mongodb, postgres, documentation, Content Management System, cms, headless, typescript, node, react, nextjs
desc: With Payload, you bring your own database and own your data. You have full control.
---

View File

@@ -3,7 +3,7 @@ title: Postgres
label: Postgres
order: 50
desc: Payload supports Postgres through an officially supported Drizzle database adapter.
keywords: Postgres, documentation, typescript, Content Management System, cms, headless, javascript, node, react, express
keywords: Postgres, documentation, typescript, Content Management System, cms, headless, javascript, node, react, nextjs
---
To use Payload with Postgres, install the package `@payloadcms/db-postgres`. It leverages Drizzle ORM and `node-postgres` to interact with a Postgres database that you provide.

View File

@@ -2,7 +2,7 @@
title: Transactions
label: Transactions
order: 30
keywords: database, transactions, sql, mongodb, postgres, documentation, Content Management System, cms, headless, typescript, node, react, express
keywords: database, transactions, sql, mongodb, postgres, documentation, Content Management System, cms, headless, typescript, node, react, nextjs
desc: Database transactions are fully supported within Payload.
---

View File

@@ -3,7 +3,7 @@ title: Email Functionality
label: Overview
order: 10
desc: Payload uses an adapter pattern to enable email functionality. Set up email functions such as password resets, order confirmations and more.
keywords: email, overview, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: email, overview, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
## Introduction

View File

@@ -0,0 +1,40 @@
---
title: Examples
label: Overview
order: 10
desc:
keywords: example, examples, starter, boilerplate, template, templates
---
Payload provides a vast array of examples to help you get started with your project no matter what you are working on. These examples are designed to be easy to get up and running, and to be easy to understand. They showcase nothing more than the specific features being demonstrated so you can easily decipher what is going on.
Examples are changing every day, so be sure to check back often to see what new examples have been added. If you have a specific example you would like to see, please feel free to start a new [Discussion](https://github.com/payloadcms/payload/discussions) or open a new [PR](https://github.com/payloadcms/payload/pulls) to add it yourself.
- [Auth](https://github.com/payloadcms/payload/tree/main/examples/auth)
- [Custom Server](https://github.com/payloadcms/payload/tree/main/examples/custom-server)
- [Draft Preview](https://github.com/payloadcms/payload/tree/main/examples/draft-preview)
- [Email](https://github.com/payloadcms/payload/tree/main/examples/email)
- [Form Builder](https://github.com/payloadcms/payload/tree/main/examples/form-builder)
- [Hierarchy](https://github.com/payloadcms/payload/tree/main/examples/hierarchy)
- [Live Preview](https://github.com/payloadcms/payload/tree/main/examples/live-preview)
- [Multi-tenant](https://github.com/payloadcms/payload/tree/main/examples/multi-tenant)
- [Nested Docs](https://github.com/payloadcms/payload/tree/main/examples/nested-docs)
- [Redirects](https://github.com/payloadcms/payload/tree/main/examples/redirects)
- [Tailwind / Shadcn-ui](https://github.com/payloadcms/payload/tree/main/examples/tailwind-shadcn-ui)
- [Tests](https://github.com/payloadcms/payload/tree/main/examples/testing)
- [Virtual Fields](https://github.com/payloadcms/payload/tree/main/examples/virtual-fields)
- [White-label Admin UI](https://github.com/payloadcms/payload/tree/main/examples/whitelabel)
When necessary, some examples include a front-end. Examples that require a front-end share this folder structure:
```plaintext
example/
├── payload/
├── next-app/
├── next-pages/
├── react-router/
├── vue/
├── svelte/
```
...where `payload` is your Payload project, and the other directories are dedicated to their respective front-end framework. We are adding new examples every day, so if your framework of choice is not yet supported in any particular example, please feel free to start a new [Discussion](https://github.com/payloadcms/payload/discussions) or open a new [PR](https://github.com/payloadcms/payload/pulls) to add it yourself.

View File

@@ -3,7 +3,7 @@ title: Array Field
label: Array
order: 20
desc: Array fields are intended for sets of repeating fields, that you define. Learn how to use array fields, see examples and options.
keywords: array, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: array, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Blocks Field
label: Blocks
order: 30
desc: The Blocks field type is a great layout build and can be used to construct any flexible content model. Learn how to use Block fields, see examples and options.
keywords: blocks, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: blocks, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Checkbox Field
label: Checkbox
order: 40
desc: Checkbox field types allow the developer to save a boolean value in the database. Learn how to use Checkbox fields, see examples and options.
keywords: checkbox, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: checkbox, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>The Checkbox field type saves a boolean in the database.</Banner>

View File

@@ -4,7 +4,7 @@ label: Code
order: 50
desc: The Code field type will store any string in the Database. Learn how to use Code fields, see examples and options.
keywords: code, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: code, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Collapsible Field
label: Collapsible
order: 60
desc: With the Collapsible field, you can place fields within a collapsible layout component that can be collapsed / expanded.
keywords: row, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: row, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Date Field
label: Date
order: 70
desc: The Date field type stores a Date in the database. Learn how to use and customize the Date field, see examples and options.
keywords: date, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: date, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Email Field
label: Email
order: 80
desc: The Email field enforces that the value provided is a valid email address. Learn how to use Email fields, see examples and options.
keywords: email, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: email, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>The Email field enforces that the value provided is a valid email address.</Banner>

View File

@@ -3,7 +3,7 @@ title: Group Field
label: Group
order: 90
desc: The Group field allows other fields to be nested under a common property. Learn how to use Group fields, see examples and options.
keywords: group, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: group, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -4,7 +4,7 @@ label: JSON
order: 50
desc: The JSON field type will store any string in the Database. Learn how to use JSON fields, see examples and options.
keywords: json, jsonSchema, schema, validation, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: json, jsonSchema, schema, validation, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Number Field
label: Number
order: 100
desc: Number fields store and validate numeric data. Learn how to use and format Number fields, see examples and Number field options.
keywords: number, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: number, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Fields Overview
label: Overview
order: 10
desc: Fields are the building blocks of Payload, find out how to add or remove a field, change field type, add hooks, define access control and validation.
keywords: overview, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: overview, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner type="info">

View File

@@ -4,7 +4,7 @@ label: Point
order: 110
desc: The Point field type stores coordinates in the database. Learn how to use Point field for geolocation and geometry.
keywords: point, geolocation, geospatial, geojson, 2dsphere, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: point, geolocation, geospatial, geojson, 2dsphere, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Radio Group Field
label: Radio Group
order: 120
desc: The Radio field type allows for the selection of one value from a predefined set of possible values. Learn how to use Radio fields, see examples and options.
keywords: radio, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: radio, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Relationship Field
label: Relationship
order: 130
desc: The Relationship field provides the ability to relate documents together. Learn how to use Relationship fields, see examples and options.
keywords: relationship, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: relationship, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Rich Text Field
label: Rich Text
order: 140
desc: The Rich Text field allows dynamic content to be written through the Admin Panel. Learn how to use Rich Text fields, see examples and options.
keywords: rich text, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: rich text, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Row Field
label: Row
order: 150
desc: With the Row field you can arrange fields next to each other in the Admin Panel to help you customize your Dashboard.
keywords: row, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: row, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Select Field
label: Select
order: 160
desc: The Select field provides a dropdown-style interface for choosing options from a predefined list. Learn how to use Select fields, see examples and options.
keywords: select, multi-select, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: select, multi-select, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Tabs Field
label: Tabs
order: 170
desc: The Tabs field is a great way to organize complex editing experiences into specific tab-based areas.
keywords: tabs, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: tabs, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Text Field
label: Text
order: 180
desc: Text field types simply save a string to the database and provide the Admin panel with a text input. Learn how to use Text fields, see examples and options.
keywords: text, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: text, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Textarea Field
label: Textarea
order: 190
desc: Textarea field types save a string to the database, similar to the Text field type but equipped for longer text. Learn how to use Textarea fields, see examples and options.
keywords: textarea, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: textarea, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: UI Field
label: UI
order: 200
desc: UI fields are purely presentational and allow developers to customize the admin panel to a very fine degree, including adding actions and other functions.
keywords: custom field, react component, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: custom field, react component, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Upload Field
label: Upload
order: 210
desc: Upload fields will allow a file to be uploaded, only from a collection supporting Uploads. Learn how to use Upload fields, see examples and options.
keywords: upload, images media, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: upload, images media, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -3,7 +3,7 @@ title: Payload Concepts
label: Concepts
order: 20
desc: Payload is based around a small and intuitive set of concepts. Key concepts include collections, globals, fields and more.
keywords: documentation, getting started, guide, Content Management System, cms, headless, javascript, node, react, express
keywords: documentation, getting started, guide, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload is based around a small and intuitive set of concepts. Before starting to work with Payload, it's a good idea to familiarize yourself with the following:

View File

@@ -3,7 +3,7 @@ title: Installation
label: Installation
order: 30
desc: To quickly get started with Payload, simply run npx create-payload-app or install from scratch.
keywords: documentation, getting started, guide, Content Management System, cms, headless, javascript, node, react, express
keywords: documentation, getting started, guide, Content Management System, cms, headless, javascript, node, react, nextjs
---
## Software Requirements
@@ -30,7 +30,7 @@ Then just follow the prompts! You'll get set up with a new folder and a function
## Adding to an existing app
Adding Payload to either a new or existing TypeScript + Express app is super straightforward. To add to an existing app, just run `npm install --save --legacy-peer-deps payload`.
Adding Payload to either a new or existing TypeScript + Next.js app is super straightforward. To add to an existing app, just run `npm install --save --legacy-peer-deps payload`.
From there, the first step is writing a baseline config. Create a new `payload.config.ts` in your project's `/src` directory (or whatever your root TS dir is). The simplest config contains the following:

View File

@@ -3,7 +3,7 @@ title: What is Payload?
label: What is Payload?
order: 10
desc: Payload is a next-gen headless Content Management System (CMS) and application framework.
keywords: documentation, getting started, guide, Content Management System, cms, headless, javascript, node, react, express
keywords: documentation, getting started, guide, Content Management System, cms, headless, javascript, node, react, nextjs
---
<YouTube

View File

@@ -3,7 +3,7 @@ title: Adding your own Queries and Mutations
label: Custom Queries and Mutations
order: 20
desc: Payload allows you to add your own GraphQL queries and mutations, simply set up GraphQL in your main Payload config by following these instructions.
keywords: graphql, resolvers, mutations, custom, queries, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: graphql, resolvers, mutations, custom, queries, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
You can add your own GraphQL queries and mutations to Payload, making use of all the types that Payload has defined for you.

View File

@@ -3,7 +3,7 @@ title: GraphQL Schema
label: GraphQL Schema
order: 30
desc: Output your own GraphQL schema based on your collections and globals to a file.
keywords: headless cms, typescript, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: headless cms, typescript, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
When working with GraphQL it is useful to have the schema for development of other projects that need to call on your GraphQL endpoint. In Payload the schema is controlled by your collections and globals and is made available to the developer or third parties, it is not necessary for developers using Payload to write schema types manually.

View File

@@ -3,7 +3,7 @@ title: GraphQL Overview
label: Overview
order: 10
desc: Payload ships with a fully featured and extensible GraphQL API, which can be used in addition to the REST and Local APIs to give you more flexibility.
keywords: graphql, resolvers, mutations, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: graphql, resolvers, mutations, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
In addition to its REST and Local APIs, Payload ships with a fully featured and extensible GraphQL API.

View File

@@ -3,7 +3,7 @@ title: Collection Hooks
label: Collections
order: 20
desc: You can add hooks to any Collection, several hook types are available including beforeChange, afterRead, afterDelete and more.
keywords: hooks, collections, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: hooks, collections, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Collections feature the ability to define the following hooks:
@@ -75,7 +75,7 @@ import { CollectionBeforeOperationHook } from 'payload/types'
const beforeOperationHook: CollectionBeforeOperationHook = async ({
args, // original arguments passed into the operation
operation, // name of the operation
req, // full express request
req, // full Request object
}) => {
return args // return modified operation arguments as necessary
}
@@ -96,7 +96,7 @@ import { CollectionBeforeValidateHook } from 'payload/types'
const beforeValidateHook: CollectionBeforeValidateHook = async ({
data, // incoming data to update or create with
req, // full express request
req, // full Request object
operation, // name of the operation ie. 'create', 'update'
originalDoc, // original document
}) => {
@@ -113,7 +113,7 @@ import { CollectionBeforeChangeHook } from 'payload/types'
const beforeChangeHook: CollectionBeforeChangeHook = async ({
data, // incoming data to update or create with
req, // full express request
req, // full Request object
operation, // name of the operation ie. 'create', 'update'
originalDoc, // original document
}) => {
@@ -130,7 +130,7 @@ import { CollectionAfterChangeHook } from 'payload/types'
const afterChangeHook: CollectionAfterChangeHook = async ({
doc, // full document data
req, // full express request
req, // full Request object
previousDoc, // document data before updating the collection
operation, // name of the operation ie. 'create', 'update'
}) => {
@@ -147,7 +147,7 @@ import { CollectionBeforeReadHook } from 'payload/types'
const beforeReadHook: CollectionBeforeReadHook = async ({
doc, // full document data
req, // full express request
req, // full Request object
query, // JSON formatted query
}) => {
return doc
@@ -163,7 +163,7 @@ import { CollectionAfterReadHook } from 'payload/types'
const afterReadHook: CollectionAfterReadHook = async ({
doc, // full document data
req, // full express request
req, // full Request object
query, // JSON formatted query
findMany, // boolean to denote if this hook is running against finding one, or finding many
}) => {
@@ -179,7 +179,7 @@ Runs before the `delete` operation. Returned values are discarded.
import { CollectionBeforeDeleteHook } from 'payload/types';
const beforeDeleteHook: CollectionBeforeDeleteHook = async ({
req, // full express request
req, // full Request object
id, // id of document to delete
}) => {...}
```
@@ -192,7 +192,7 @@ Runs immediately after the `delete` operation removes records from the database.
import { CollectionAfterDeleteHook } from 'payload/types';
const afterDeleteHook: CollectionAfterDeleteHook = async ({
req, // full express request
req, // full Request object
id, // id of document to delete
doc, // deleted document
}) => {...}
@@ -210,7 +210,7 @@ import { CollectionAfterOperationHook } from 'payload/types'
const afterOperationHook: CollectionAfterOperationHook = async ({
args, // arguments passed into the operation
operation, // name of the operation
req, // full express request
req, // full Request object
result, // the result of the operation, before modifications
}) => {
return result // return modified result as necessary
@@ -225,7 +225,7 @@ For auth-enabled Collections, this hook runs during `login` operations where a u
import { CollectionBeforeLoginHook } from 'payload/types'
const beforeLoginHook: CollectionBeforeLoginHook = async ({
req, // full express request
req, // full Request object
user, // user being logged in
}) => {
return user
@@ -240,7 +240,7 @@ For auth-enabled Collections, this hook runs after successful `login` operations
import { CollectionAfterLoginHook } from 'payload/types';
const afterLoginHook: CollectionAfterLoginHook = async ({
req, // full express request
req, // full Request object
user, // user that was logged in
token, // user token
}) => {...}
@@ -254,7 +254,7 @@ For auth-enabled Collections, this hook runs after `logout` operations.
import { CollectionAfterLogoutHook } from 'payload/types';
const afterLogoutHook: CollectionAfterLogoutHook = async ({
req, // full express request
req, // full Request object
}) => {...}
```
@@ -266,8 +266,8 @@ For auth-enabled Collections, this hook runs after `refresh` operations.
import { CollectionAfterRefreshHook } from 'payload/types';
const afterRefreshHook: CollectionAfterRefreshHook = async ({
req, // full express request
res, // full express response
req, // full Request object
res, // full Response object
token, // newly refreshed user token
}) => {...}
```
@@ -280,7 +280,7 @@ For auth-enabled Collections, this hook runs after `me` operations.
import { CollectionAfterMeHook } from 'payload/types';
const afterMeHook: CollectionAfterMeHook = async ({
req, // full express request
req, // full Request object
response, // response to return
}) => {...}
```

View File

@@ -3,7 +3,7 @@ title: Field Hooks
label: Fields
order: 30
desc: Hooks can be added to any fields, and optionally modify the return value of the field before the operation continues.
keywords: hooks, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: hooks, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Field-level hooks offer incredible potential for encapsulating your logic. They help to isolate concerns and package up
@@ -74,7 +74,7 @@ Field Hooks receive one `args` argument that contains the following properties:
| **`originalDoc`** | The full original document in `update` operations. In the `afterChange` hook, this is the resulting document of the operation. |
| **`previousDoc`** | The document before changes were applied, only in `afterChange` hooks. |
| **`previousSiblingDoc`** | The sibling data of the document before changes being applied, only in `beforeChange` and `afterChange` hook. |
| **`req`** | The Express `request` object. It is mocked for Local API operations. |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. It is mocked for Local API operations. |
| **`value`** | The value of the field. |
| **`previousValue`** | The previous value of the field, before changes, only in `beforeChange` and `afterChange` hooks. |
| **`context`** | Context passed to this hook. More info can be found under [Context](/docs/hooks/context) |

View File

@@ -3,7 +3,7 @@ title: Global Hooks
label: Globals
order: 40
desc: Hooks can be added to any Global and allow you to validate data, flatten locales, hide protected fields, remove fields and more.
keywords: hooks, globals, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: hooks, globals, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Globals feature the ability to define the following hooks:
@@ -47,7 +47,7 @@ import { GlobalBeforeValidateHook } from 'payload/types'
const beforeValidateHook: GlobalBeforeValidateHook = async ({
data, // incoming data to update or create with
req, // full express request
req, // full Request object
originalDoc, // original document
}) => {
return data // Return data to update the document with
@@ -63,7 +63,7 @@ import { GlobalBeforeChangeHook } from 'payload/types'
const beforeChangeHook: GlobalBeforeChangeHook = async ({
data, // incoming data to update or create with
req, // full express request
req, // full Request object
originalDoc, // original document
}) => {
return data // Return data to update the document with
@@ -80,7 +80,7 @@ import { GlobalAfterChangeHook } from 'payload/types'
const afterChangeHook: GlobalAfterChangeHook = async ({
doc, // full document data
previousDoc, // document data before updating the collection
req, // full express request
req, // full Request object
}) => {
return data
}
@@ -95,7 +95,7 @@ import { GlobalBeforeReadHook } from 'payload/types'
const beforeReadHook: GlobalBeforeReadHook = async ({
doc, // full document data
req, // full express request
req, // full Request object
}) => {...}
```
@@ -108,7 +108,7 @@ import { GlobalAfterReadHook } from 'payload/types'
const afterReadHook: GlobalAfterReadHook = async ({
doc, // full document data
req, // full express request
req, // full Request object
findMany, // boolean to denote if this hook is running against finding one, or finding many (useful in versions)
}) => {...}
```

View File

@@ -3,7 +3,7 @@ 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.
keywords: hooks, overview, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: hooks, overview, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner type="info">
@@ -36,7 +36,7 @@ If your Hook simply performs a side-effect, such as updating a CRM, it might be
## Server-only execution
Payload Hooks are only triggered on the server. You can safely [remove your hooks](/docs/admin/webpack#aliasing-server-only-modules) from your Admin panel's client-side code by customizing the Webpack config, which not only keeps your Admin bundles' filesize small but also ensures that any server-side only code does not cause problems within browser environments.
Payload Hooks are only triggered on the server and are automatically excluded from the Payload Admin bundle.
## Hook Types

View File

@@ -3,7 +3,7 @@ title: Vercel Content Link
label: Vercel Content Link
order: 10
desc: Payload + Vercel Content Link allows yours editors to navigate directly from the content rendered on your front-end to the fields in Payload that control it.
keywords: vercel, vercel content link, visual editing, content source maps, Content Management System, cms, headless, javascript, node, react, express
keywords: vercel, vercel content link, content link, visual editing, content source maps, Content Management System, cms, headless, javascript, node, react, nextjs
---
[Vercel Content Link](https://vercel.com/docs/workflow-collaboration/edit-mode#content-link) will allow your editors to navigate directly from the content rendered on your front-end to the fields in Payload that control it. This requires no changes to your front-end code and very few changes to your Payload config.

View File

@@ -7,7 +7,7 @@ keywords: live preview, frontend, react, next.js, vue, nuxt.js, svelte, hook, us
---
<Banner type="info">
If your front-end application supports Server Components like the [Next.js App Router](https://nextjs.org/docs/app), etc., we suggest setting up [server-side Live Preview](./server).
If your front-end application supports Server Components like the [Next.js App Router](https://nextjs.org/docs/app), etc., we suggest setting up [server-side Live Preview](./server) instead.
</Banner>
While using Live Preview, the Admin panel emits a new `window.postMessage` event every time your document has changed. Your front-end application can listen for these events and re-render accordingly.

View File

@@ -6,11 +6,11 @@ desc: Learn how to implement Live Preview in your front-end application.
keywords: live preview, frontend, react, next.js, vue, nuxt.js, svelte, hook, useLivePreview
---
There are two ways to use Live Preview in your own application depending on whether your front-end framework supports server components:
There are two ways to use Live Preview in your own application depending on whether your front-end framework supports Server Components:
- [Server-side Live Preview (suggested)](./server)
- [Client-side Live Preview](./client)
<Banner type="info">
We suggest using server-side Live Preview if your framework supports it, it is both simpler to setup and more performant to run than the client-side alternative.
We suggest using server-side Live Preview if your framework supports Server Components, it is both simpler to setup and more performant to run than the client-side alternative.
</Banner>

View File

@@ -20,7 +20,7 @@ If your front-end application is built with [React](#react), you can use the `Re
## React
If your front-end application is built with [React](https://react.dev) or [Next.js](https://nextjs.org), you can use the `RefreshRouteOnSave` component that Payload provides.
If your front-end application is built with server-side [React](https://react.dev) like [Next.js App Router](https://nextjs.org/docs/app), you can use the `RefreshRouteOnSave` component that Payload provides.
First, install the `@payloadcms/live-preview-react` package:
@@ -28,7 +28,7 @@ First, install the `@payloadcms/live-preview-react` package:
npm install @payloadcms/live-preview-react
```
Then, render `RefreshRouteOnSave` anywhere in your `page.tsx`. Here's an example:
Then, render the `RefreshRouteOnSave` component anywhere in your `page.tsx`. Here's an example:
`page.tsx`:
@@ -64,7 +64,13 @@ import React from 'react'
export const RefreshRouteOnSave: React.FC = () => {
const router = useRouter()
return <PayloadLivePreview refresh={router.refresh} serverURL={process.env.PAYLOAD_SERVER_URL} />
return (
<PayloadLivePreview
refresh={() => router.refresh()}
serverURL={process.env.NEXT_PUBLIC_PAYLOAD_URL}
/>
)
}
```
@@ -153,13 +159,15 @@ export const RefreshRouteOnSave: React.FC<{
## Example
{/* TODO: add example once beta has been release and an example can be created */}
For a working demonstration of this, check out the official [Live Preview Example](https://github.com/payloadcms/payload/tree/main/examples/live-preview/payload). There you will find a fully working example of how to implement Live Preview in your Next.js App Router application.
## Troubleshooting
### Updates do not appear as fast as client-side Live Preview
If you are noticing that updates feel less snappy than client-side Live Preview (i.e. the `useLivePreview` hook), this is because of how the two differ in how they work—instead of emitting events against form state as you type, server-side Live Preview refreshes the route after a new document is saved. You can use autosave to mimic this effect. Try decreasing the value of `versions.autoSave.interval` to make the experience feel more responsive:
If you are noticing that updates feel less snappy than client-side Live Preview (i.e. the `useLivePreview` hook), this is because of how the two differ in how they work—instead of emitting events against _form state_, server-side Live Preview refreshes the route after a new document is _saved_.
Use [Autosave](../versions/autosave) to mimic this effect server-side. Try decreasing the value of `versions.autoSave.interval` to make the experience feel more responsive:
```ts
// collection.ts

View File

@@ -3,7 +3,7 @@ title: Local API
label: Overview
order: 10
desc: The Payload Local API allows you to interact with your database and execute the same operations that are available through REST and GraphQL within Node, directly on your server.
keywords: local api, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: local api, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Payload Local API gives you the ability to execute the same operations that are available through REST and GraphQL
@@ -23,7 +23,7 @@ can interact directly with your database.
Here are some common examples of how you can use the Local API:
- Seeding data via Node seed scripts that you write and maintain
- Opening custom Express routes which feature additional functionality but still rely on Payload
- Opening custom routes which feature additional functionality but still rely on Payload
- Within access control and hook functions
## Accessing payload
@@ -51,7 +51,7 @@ const afterChangeHook: CollectionAfterChangeHook = async () => {
#### Accessing from the `req`
Payload is available anywhere you have access to the Express `req` - including within your access control and hook
Payload is available anywhere you have access to the `req` - including within your access control and hook
functions.
Example:
@@ -310,7 +310,7 @@ const result = await payload.login({
email: 'dev@payloadcms.com',
password: 'rip',
},
req: req, // pass an Express `req` which will be provided to all hooks
req: req, // pass a Request object to be provided to all hooks
res: res, // used to automatically set an HTTP-only auth cookie
depth: 2,
locale: 'en',
@@ -330,7 +330,7 @@ const token = await payload.forgotPassword({
// required
email: 'dev@payloadcms.com',
},
req: req, // pass an Express `req` which will be provided to all hooks
req: req, // pass a Request object to be provided to all hooks
})
```
@@ -349,7 +349,7 @@ const result = await payload.resetPassword({
password: req.body.password, // the new password to set
token: 'afh3o2jf2p3f...', // the token generated from the forgotPassword operation
},
req: req, // pass an Express `req` which will be provided to all hooks
req: req, // pass a Request object to be provided to all hooks
res: res, // used to automatically set an HTTP-only auth cookie
})
```
@@ -364,7 +364,7 @@ const result = await payload.unlock({
// required
email: 'dev@payloadcms.com',
},
req: req, // pass an Express `req` which will be provided to all hooks
req: req, // pass a Request object to be provided to all hooks
overrideAccess: true,
})
```
@@ -427,10 +427,10 @@ const result = await payload.updateGlobal({
## Next.js Conflict with Local API
There is a known issue when using the Local API with Next.js version `13.4.13` and higher. Next.js executes within a
separate child process, and Payload has not been initalized yet in these instances. That means that unless you
separate child process, and Payload has not been initialized yet in these instances. That means that unless you
explicitly initialize Payload within your operation, it will not be running and return no data / an empty object.
As a workaround, we recommend leveraging the following pattern to determine and ensure Payload is initalized:
As a workaround, we recommend leveraging the following pattern to determine and ensure Payload is initialized:
```
import dotenv from 'dotenv'

View File

@@ -0,0 +1,804 @@
# 🚧 **DRAFT:** 3.0 Migration Guide / Breaking Changes
> [!IMPORTANT]
> This document will continue to be updated and cleaned up until the 3.0 release.
## What has changed?
The core logic and principles of Payload remain the same for 3.0. The brunt of the changes are at the HTTP layer and the Admin Panel. These aspects were moved to be based upon Next.js.
## To migrate from Payload 2.0 to 3.0:
1. Delete the `admin.bundler` property from your Payload config:
Payload no longer bundles the admin panel. Instead, we rely directly on Next.js for bundling. This also means that the `@payloadcms/bundler-webpack` and `@payloadcms/bundler-vite` packages have been deprecated. You can completely uninstall those from your project by removing them from your `package.json` file and re-running your package managers installation process, i.e. `pnpm i`.
2. Add the `secret` property to your Payload config. This used to be set in the `payload.init()` function of your `server.ts` file. Move it to `payload.config.ts` instead:
```tsx
// payload.config.ts
buildConfig({
// ...
secret: process.env.PAYLOAD_SECRET
})
```
3. The `admin.css` and `admin.scss` properties in the Payload config have been removed:
Instead for any global styles you can:
- use `(payload)/custom.scss` to import or add your own styles, eg. for tailwind
- plugins that need to inject global styles should do so via the provider config at `admin.components.providers` :
```tsx
// payload.config.js
//...
admin: {
components: {
providers: [
MyProvider
]
}
},
//...
// MyProvider.tsx
import React from 'react'
import './globals.css'
const MyProvider: React.FC<{children?: any}= ({ children }) ={
return (
<React.fragment>
{children}
</React.fragment>
)
}
export default Provider
```
4. The `admin.indexHTML` property has been removed.
5. The `collection.admin.hooks` property has been removed.
Instead, use the new `beforeDuplicate` field-level hook which take the usual field hook arguments.
```tsx
// TODO: add snippet here of old vs new
```
6. Import all Payload React components via the `@payloadcms/ui` package instead of `payload`:
If you were previously importing components into your app from the `payload` package, for example to create a custom component, you will need to:
- Change your import paths (see below)
- Migrate your component (if necessary, see next bullet)
```tsx
import { Button } from '@payloadcms/ui/elements/Button'
// TODO: Add new full list of exports
```
7. Migrate all Custom Components to Server Components.
All Custom Components are now server-rendered, and therefore, cannot use state or hooks directly. If youre using Custom Components in your app that requires state or hooks, define your component in a separate file with the `'use client'` directive at the top, then render *that* client component within your server component. Remember you can only pass serializable props to this component, so props cannot be blindly spread.
```tsx
import React from 'react'
import type { ServerOnlyProps } from './types.ts'
import MyClientComponent from './client.tsx'
export const MyServerComponent: React.FC<ServerOnlyProps= (serverOnlyProps) ={
const clientOnlyProps = {
// ... sanitize server-only props here as needed
}
return (
<MyClientComponent {...clientOnlyProps} />
)
}
```
8. The `custom` property in the Payload config, i.e. collections, globals, blocks, and fields are now ***server only***.
Use `admin.custom` properties will be available in both server and client bundles.
```tsx
// payload.config.ts
buildConfig({
// Server Only
custom: {
someProperty: 'value'
},
admin: {
custom: {
name: 'Customer portal' // Available in server and client
}
},
})
```
9. The `admin.description` property on field configs no longer attaches `data` to its args:
This is because we cannot pass your `description` function to the client for execution (functions are not serializable, and state is held on the client). To display dynamic descriptions that use current `data` or `path`, you must now pass a custom component and subscribe to the fields state yourself using Payloads React hooks:
```tsx
// TODO: add config snippet for total clarity
import React from 'react'
// TODO: get rest of imports
export const CustomFieldDescriptionComponent: DescriptionComponent = () ={
const { path } = useFieldProps()
const { value } = useFormFields(([fields]) =fields[path])
return (
<div>
{`Component description: ${path} - ${value}`}
</div>
)
}
```
10. The `admin.label` property on the `collapsible` field no longer attaches `data` to its args.
This is because we cannot pass your `label` function to the client for execution (functions are not serializable, and state is held on the client). To display dynamic labels that use current `data` or `path`, you must now pass a custom component and subscribe to the fields state yourself using Payloads React hooks:
```tsx
// TODO: add config snippet for total clarity
import React from 'react'
// TODO: get rest of imports
export const CustomFieldLabelComponent: LabelComponent = () => {
const { path } = useFieldProps()
const { value } = useFormFields(([fields]) =fields[path])
return (
<div>
{`Component label: ${path} - ${value}`}
</div>
)
}
```
11. The `admin.components.Cell` no longer receives `rowData` or `cellData`.
If using a custom component, you must now get the data yourself via the `useTableCell` hook, i.e. `const { cellData, rowData } = useTableCell()`.
```tsx
// TODO: add config snippet for total clarity
import React from 'react'
// TODO: get rest of imports
export const CustomCellComponent: CellComponent = () ={
const { cellData, rowData } = useTableCell()
return (
<div>
{`Component cell: ${cellData}`}
</div>
)
}
```
12. `admin.components.RowLabel` no longer accepts a function, instead use a custom component and make use of the `useRowLabel` hook:
```tsx
// ❌ Before
// Field config
{
type: 'array',
admin: {
components: {
RowLabel: ({ data }) ={
console.log(data)
return data?.title || 'Untitled'
},
}
}
}
```
```tsx
// ✅ After
// Field config
{
type: 'array',
admin: {
components: {
RowLabel: ArrayRowLabel
}
}
}
// Custom Component
'use client'
import type { RowLabelComponent } from 'payload/types'
import { useRowLabel } from '@payloadcms/ui/forms/RowLabel/Context'
import React from 'react'
export const ArrayRowLabel: RowLabelComponent = () ={
const { data } = useRowLabel<{ title: string }>()
return (
<div>{data.title || 'Untitled'}</div>
)
}
```
13. The `admin.components.views[].Tab.pillLabel` has been replaced with `admin.components.views[].Tab.Pill`
```tsx
// Collection.ts
// ❌ Before
{
admin: {
components: {
views: {
Edit: {
Tab: {
pillLabel: '',
},
},
},
},
},
}
// ✅ After
{
admin: {
components: {
views: {
Edit: {
Tab: {
Pill: MyPill,
},
},
},
},
},
}
```
14. The `useTitle` hook has been absorbed by the `useDocumentInfo` hook.
Now, you can get title directly from document info context, i.e. `const { title } = useDocumentInfo()`.
15. The `Fields` type was renamed to `FormState`:
This was changed for improved semantics. If you were previously importing this type in your own application, simply change the import name:
```tsx
// ❌ Before
import type { Fields } from 'payload/types'
// ✅ After
import type { FormState } from 'payload/types'
```
16. The `useDocumentInfo` hook no longer returns a `SanizitedCollectionConfig` or `SanitizedGlobalConfig`:
This is because the configs themselves are not serializable and so they cannot be thread through to the client, i.e. the `DocumentInfoContext`. Instead, various properties of the config are passed instead, like `collectionSlug` and `globalSlug`. You can use these to access a client-side config, if needed, through the `useConfig` hook (see next bullet).
17. The `useConfig` hook now returns a `ClientConfig` and not a `SanizitedConfig`.
This is because the config itself is not serializable and so it is not able to be thread through to the client, i.e. the `ConfigContext`.
18. `DocumentTabProps` no longer contains `id` or `isEditing`.
Instead you can use the `useDocumentInfo` hook to get this information (see above).
19. The args of the `livePreview.url` function have changed.
It no longer receives `documentInfo` as an arg, and instead, now has `collectionConfig` and `globalConfig`.
20. The `href` and `isActive` functions in the view tab config no longer sends the `match` or `location` arguments.
This is is a property specific to React Router, not Next.js. If you need to do fancy matching similar to this, use a custom tab that fires of some hooks, i.e. `usePathname()` and run it through your own utility functions.
21. The `views.Edit` or `views.Edit.Default` or `views.Edit.Default.Component` properties are no longer of type `AdminViewComponent` like the other views.
Instead, their new type is `React.FC<EditViewProps>` where you now only receive the config slug. This is because of how custom edit views need to be rendered server-side, then returned by a client-component (i.e. the document drawer). Theres an example of this adapter pattern in the first sections of this page.
22. `beforeDuplicate` field hooks have been added to `unique` fields to automatically add “- Copy” to the end.
23. The `useCollapsible` hook has had slight changes to its property names:
`collapsed` is now `isCollapsed` and `withinCollapsible` is now `isWithinCollapsible`.
24. Components that return a function have webpack errors.
Will need to document the following (if intended as a breaking change)
![Untitled](https://prod-files-secure.s3.us-west-2.amazonaws.com/0fcec415-321b-48ca-a915-504d61c448b3/94156826-74ee-4708-aa73-1beb11ad0306/Untitled.png)
25. The `admin.favicon` property is now `admin.icons` and the types have changed
Reference: https://github.com/payloadcms/payload/pull/6347
```tsx
// payload.config.ts
// ❌ Before
{
// ...
admin: {
favicon: 'path-to-favicon.svg'
}
}
// ✅ After
{
// ...
admin: {
icons: [{
path: 'path-to-favicon.svg',
sizes: '32x32'
}]
}
}
```
See also: https://nextjs.org/docs/app/api-reference/functions/generate-metadata#icons
26. The `admin.meta.ogImage` property has been replaced by `admin.meta.openGraph.images`
Reference: https://github.com/payloadcms/payload/pull/6227
```tsx
// payload.config.ts
// ❌ Before
{
admin: {
meta: {
ogImage: ''
}
}
}
```
```tsx
// ✅ After
{
admin: {
meta: {
openGraph: {
images: []
}
}
}
}
```
See also : https://nextjs.org/docs/app/api-reference/functions/generate-metadata#opengraph
27. The `admin.logoutRoute` and `admin.inactivityRoute` properties have been consolidated into a single `admin.routes` property
Reference: https://github.com/payloadcms/payload/pull/6354
To migrate, simply move those two keys as follows:
```tsx
// payload.config.ts
// ❌ Before
{
// ...
admin: {
logoutRoute: '/custom-logout',
inactivityRoute: '/custom-inactivity'
}
}
// ✅ After
{
// ...
admin: {
routes: {
logout: '/custom-logout',
inactivity: '/custom-inactivity'
}
}
}
```
## Environment variables
- Environment variables prefixed with `PAYLOAD_PUBLIC` will no longer be available on the client. In order to access them on the client, those will now have to be prefixed with `NEXT_PUBLIC` instead
## i18n
- `useTranslation()` hook no longer takes any options, any translations using shorthand accessors will need to use the entire `group:key`
```tsx
// ❌ Before
const { i18n, t } = useTranslation('general')
return <p>{t('cancel')}</p>
// ✅ After
const { i18n, t } = useTranslation()
return <p>{t('general:cancel')}</p>
```
- `react-i18n` was removed, the `Trans` component from react-i18n has been replaced with a payload provided solution. You can instead `import { Translation } from "@payloadcms/ui"`
```tsx
// Translation string example
// "loggedInChangePassword": "To change your password, go to your <0>account</0> and edit your password there."
// ❌ Before
<Trans i18nKey="loggedInChangePassword" t={t}>
<Link to={`${admin}/account`}>account</Link>
</Trans>
// ✅ After
<Translation
t={t}
i18nKey="authentication:loggedInChangePassword"
elements={{
'0': ({ children }) => <Link href={`${admin}/account`} children={children} />,
}}
/>
```
## Description and Label handling
https://github.com/payloadcms/payload/pull/6264
- Globals config: `admin.description` no longer accepts a custom component. You will have to move it to `admin.components.elements.Description`
- Collections config: `admin.description` no longer accepts a custom component. You will have to move it to `admin.components.edit.Description`
- All Fields: `field.admin.description` no longer accepts a custom component. You will have to move it to `field.admin.components.Description`
- Collapsible Field: `field.label` no longer accepts a custom component. You will have to move it to `field.admin.components.RowLabel`
- Array Field: `field.admin.components.RowLabel` no longer accepts strings or records
- If you are using our exported field components in your own app, their `labelProps` property has been stripped down and no longer contains the `label` and `required` prop. Those can now only be configured at the top-level.
## Custom Endpoints
- `root` endpoints no longer exist on the config. If you want to create a “root” endpoint, you can add them to the api folder within your Payload application. See Next docs: https://nextjs.org/docs/app/api-reference/file-conventions/route
- Endpoint handlers
- arguments
- ❌ Before: `(req, res, next)`
- ✅ After: `(req)`
- return
- ❌ Before: `res.json`, `res.send`, etc.
- ✅ After: a valid HTTP [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
```tsx
// ❌ Before
{
path: '/whoami/:parameter',
method: 'post',
handler: (req, res) => {
res.json({
parameter: req.params.parameter,
name: req.body.name,
age: req.body.age,
})
}
}
// ✅ After
{
path: '/whoami/:parameter',
method: 'post',
handler: (req) => {
return Response.json({
parameter: req.routeParams.parameter,
// ^^ `params` is now `routeParams`
name: req.data.name,
age: req.data.age,
})
}
}
```
- Handlers no longer resolve `data` for you on the request, use `req.json()` or you can use our utilities
```tsx
// ❌ Before
{
path: '/whoami/:parameter',
method: 'post',
handler: async (req) => {
return Response.json({
name: req.data.name, // data will be undefined
})
}
}
// ✅ After
import { addDataAndFileToRequest } from '@payloadcms/next/utilities'
{
path: '/whoami/:parameter',
method: 'post',
handler: async (req) => {
// mutates req, must be awaited
await addDataAndFileToRequest(req)
return Response.json({
name: req.data.name, // data is now available
})
}
}
```
- Handlers no longer resolve `locale` and `fallbackLocale` for you
```tsx
// ❌ Before
{
path: '/whoami/:parameter',
method: 'post',
handler: async (req) => {
return Response.json({
// will be undefined
fallbackLocale: req.fallbackLocale,
locale: req.locale,
})
}
}
// ✅ After
import { addLocalesToRequest } from '@payloadcms/next/utilities'
{
path: '/whoami/:parameter',
method: 'post',
handler: async (req) => {
// mutates req
addLocalesToRequest(req)
return Response.json({
fallbackLocale: req.fallbackLocale,
locale: req.locale,
})
}
}
```
## Req (Hooks, Access-control, etc)
- The `req` used to extend the Express Request, now it extends the [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request). So you may need to change things in your code, for example if you are relying on `req.headers['content-type']` you will now need to to use `req.headers.get('content-type')`
## Uploads
- `staticDir` must now be an absolute path. Before it would attempt to use the location of the payload config and merge the relative path set for staticDir.
- `staticURL` has been removed. If you were using this format URLs when using an external provider, you can leverage the `generateFileURL` functions in order to do the same.
## Email Adapters
Email functionality has been abstracted out into email adapters.
- All existing nodemailer functionality was abstracted into the `@payloadcms/email-nodemailer` package
- No longer configured with ethereal.email by default.
- Ability to pass email into the `init` function has been removed.
- Warning will be given on startup if email not configured. Any `sendEmail` call will simply log the To address and subject.
- A Resend adapter is now also available via the `@payloadcms/email-resend` package.
### If you used the default email configuration in 2.0 (nodemailer):
```tsx
// ❌ Before
// via payload.init
payload.init({
email: {
transport: someNodemailerTransport
fromName: 'hello',
fromAddress: 'hello@example.com',
},
})
// or via email in payload.config.ts
export default buildConfig({
email: {
transport: someNodemailerTransport
fromName: 'hello',
fromAddress: 'hello@example.com',
},
})
// ✅ After
// Using new nodemailer adapter package
import { nodemailerAdapter } from '@payloadcms/email-nodemailer'
export default buildConfig({
email: nodemailerAdapter() // This will be the old ethereal.email functionality
})
// or pass in transport
export default buildConfig({
email: nodemailerAdapter({
defaultFromAddress: 'info@payloadcms.com',
defaultFromName: 'Payload',
transport: await nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: 587,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
})
})
})
```
### Removal of rate-limiting
- Now only available if using custom server and using express or similar
# Plugins
- *All* plugins have been standardized to use *named exports* (as opposed to default exports). Most also have a suffix of `Plugin` to make it clear what is being imported.
```tsx
// ❌ Before
import seo from '@payloadcms/plugin-seo'
import stripePlugin from '@payloadcms/plugin-stripe'
// ✅ After
import { seoPlugin } from '@payloadcms/plugin-seo'
import { stripePlugin } from '@payloadcms/plugin-stripe'
// etc.
```
## `@payloadcms/plugin-cloud-storage`
- The adapters that are exported from `@payloadcms/plugin-cloud-storage` (ie. `@payloadcms/plugin-cloud-storage/s3`) package have been removed.
- New *standalone* packages have been created for each of the existing adapters. Please see the documentation for the one that you use.
- `@payloadcms/plugin-cloud-storage` is still fully supported but should only to be used if you are providing a custom adapter that does not have a dedicated package.
- If you have created a custom adapter, the type must now provide a `name` property.
| Service | Package |
| -------------------- | ---------------------------------------------------------------------------- |
| Vercel Blob | https://github.com/payloadcms/payload/tree/beta/packages/storage-vercel-blob |
| AWS S3 | https://github.com/payloadcms/payload/tree/beta/packages/storage-s3 |
| Azure | https://github.com/payloadcms/payload/tree/beta/packages/storage-azure |
| Google Cloud Storage | https://github.com/payloadcms/payload/tree/beta/packages/storage-gcs |
```tsx
// ❌ Before (required peer dependencies depending on adapter)
import { cloudStorage } from '@payloadcms/plugin-cloud-storage'
import { s3Adapter } from '@payloadcms/plugin-cloud-storage/s3'
plugins: [
cloudStorage({
collections: {
[mediaSlug]: {
adapter: s3Adapter({
bucket: process.env.S3_BUCKET,
config: {
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
},
region: process.env.S3_REGION,
},
}),
},
},
}),
],
// ✅ After
import { s3Storage } from '@payloadcms/storage-s3'
plugins: [
s3Storage({
collections: {
[mediaSlug]: true,
},
bucket: process.env.S3_BUCKET,
config: {
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
},
region: process.env.S3_REGION,
},
}),
],
```
## `@payloadcms/plugin-form-builder`
- Field overrides for form and form submission collections now accept a function with a `defaultFields` inside the args instead of an array of config
```tsx
// ❌ Before
fields: [
{
name: 'custom',
type: 'text',
}
]
// ✅ After
fields: ({ defaultFields }) => {
return [
...defaultFields,
{
name: 'custom',
type: 'text',
},
]
}
```
## `@payloadcms/plugin-redirects`
- Field overrides for the redirects collection now accepts a function with a `defaultFields` inside the args instead of an array of config
```tsx
// ❌ Before
fields: [
{
name: 'custom',
type: 'text',
}
]
// ✅ After
fields: ({ defaultFields }) => {
return [
...defaultFields,
{
name: 'custom',
type: 'text',
},
]
}
```
## `@payloadcms/richtext-lexical`
// TODO: Needs comprehensive breaking changes / migration steps
### Custom Features
- Previously, a Feature would contain both server code (e.g. population promises) and client code (e.g. toolbar items). Now, they have been split up into server features and client features

View File

@@ -3,7 +3,7 @@ title: Building Your Own Plugin
label: Build Your Own
order: 50
desc: Starting to build your own plugin? Find everything you need and learn best practices with the Payload plugin template.
keywords: plugins, template, config, configuration, extensions, custom, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: plugins, template, config, configuration, extensions, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Building your own plugin is easy, and if you&apos;re already familiar with Payload then you&apos;ll have everything you need to get started. You can either start from scratch or use the Payload plugin template to get up and running quickly.
@@ -235,22 +235,6 @@ If you wish to add to the `onInit`, you must include the async/await. We don&apo
In the template, we have stubbed out a basic `onInitExtension` file that you can use, if not needed feel free to delete it.
## Webpack
If any of your files use server only packages such as fs, stripe, nodemailer, etc, they will need to be removed from the browser bundle. To do that, you can [alias the file imports with webpack](https://payloadcms.com/docs/admin/webpack#aliasing-server-only-modules).
When files are bundled for the browser, the import paths are essentially crawled to determine what files to include in the bundle. To prevent the server only files from making it into the bundle, we can alias their import paths to a file that can be included in the browser. This will short-circuit the import path crawling and ensure browser only code is bundled.
Webpack is another part of the Payload config that can be a little more tricky to extend. To help here, the template includes a helper function `extendWebpackConfig()` which takes care of spreading the existing webpack, so you can just add your new stuff:
```
config.admin = {
...(config.admin || {}),
// Add your aliases to the helper function below
webpack: extendWebpackConfig(incomingConfig)
}
```
## Types
If your plugin has options, you should define and provide types for these options in a separate file which gets exported from the main `index.ts`.
@@ -274,7 +258,7 @@ In addition to the setup covered above, here are other best practices to follow:
### Providing an enable / disable option
For a better user experience, provide a way to disable the plugin without uninstalling it. This is especially important if your plugin adds additional webpack aliases, this will allow you to still let the webpack run to prevent errors.
For a better user experience, provide a way to disable the plugin without uninstalling it.
### Include tests in your GitHub CI workflow

View File

@@ -3,7 +3,7 @@ title: Plugins
label: Overview
order: 10
desc: Plugins provide a great way to modularize Payload functionalities into easy-to-use enhancements and extensions of your Payload apps.
keywords: plugins, config, configuration, extensions, custom, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: plugins, config, configuration, extensions, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload comes with a built-in Plugins infrastructure that allows developers to build their own modular and easily reusable sets of functionality.
@@ -39,12 +39,7 @@ import passwordProtect from 'payload-password-protect'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { postgresAdapter } from '@payloadcms/db-postgres'
import { viteBundler } from '@payloadcms/bundler-vite'
import { webpackBundler } from '@payloadcms/bundler-webpack'
const config = buildConfig({
bundler: webpackBundler() // or viteBundler(),
collections: [
{
slug: 'pages',

View File

@@ -3,7 +3,7 @@ title: Production Deployment
label: Deployment
order: 10
desc: When your Payload based app is ready, tested, looking great, it is time to deploy. Learn how to deploy your app and what to consider before deployment.
keywords: deployment, production, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: deployment, production, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner type="success">
@@ -48,10 +48,14 @@ wield that power responsibly before deploying to Production.
By default, all Access Control functions require that a user is successfully logged in to
Payload to create, read, update, or delete data.
</strong>
But, if you allow public user registration, for example, you will want to make sure that your
access control functions are more strict - permitting <strong>only appropriate users</strong> to
perform appropriate actions.
access control functions are more strict - permitting
{' '}
<strong>
only appropriate users
</strong>
{' '}
to perform appropriate actions.
</Banner>
### Building the Admin panel
@@ -73,7 +77,7 @@ Payload provides the `build` NPM script. You can use it by adding a `script` to
}
```
Then, to build Payload, you would run `npm run build` in your project folder. A production-ready Admin bundle will be
Then, to build Payload, you would run `npm run build` in your project folder. A production-ready Payload Admin bundle will be
created in the `build` directory.
### Setting Node to Production
@@ -181,7 +185,7 @@ _copy_ the files your users upload to a more permanent storage solution like Ama
**To automatically send uploaded files to S3 or similar, you could:**
- Write an asynchronous `beforeChange` hook for all Collections that support Uploads, which takes any uploaded `file`
from the Express `req` and sends it to an S3 bucket
from the `req` and sends it to an S3 bucket
- Write an `afterRead` hook to save a `s3URL` field that automatically takes the `filename` stored and formats a full S3
URL
- Write an `afterDelete` hook that automatically deletes files from the S3 bucket

View File

@@ -3,7 +3,7 @@ title: Preventing Production API Abuse
label: Preventing Abuse
order: 20
desc: Payload has built-in security that can be configured to combat production API abuse such as limiting login attempts and IP requests.
keywords: abuse, production, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: abuse, production, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
## Introduction
@@ -22,7 +22,7 @@ To prevent DDoS, brute-force, and similar attacks, you can set IP-based rate lim
| ---------------- | ----------------------------------------------------------------------------------------------------------------------- |
| **`window`** | Time in milliseconds to track requests per IP. Defaults to `90000` (15 minutes). |
| **`max`** | Number of requests served from a single IP before limiting. Defaults to `500`. |
| **`skip`** | Express middleware function that can return true (or promise resulting in true) that will bypass limit. |
| **`skip`** | Function that can return true (or promise resulting in true) that will bypass limit. |
| **`trustProxy`** | True or false, to enable to allow requests to pass through a proxy such as a load balancer or an `nginx` reverse proxy. |
<Banner type="warning">
@@ -53,7 +53,7 @@ Because GraphQL gives the power of query writing outside a server's control, som
Any GraphQL request that is calculated to be too expensive is rejected. On the Payload config, in `graphQL` you can set the `maxComplexity` value as an integer. For reference, the default complexity value for each added field is 1, and all `relationship` and `upload` fields are assigned a value of 10.
If you do not need GraphQL it is advised that you disable it altogether with the Payload config by setting `graphQL.disable: true`. Should you wish to enable GraphQL again, you can remove this property or set it `false`, any time. By turning it off, Payload will bypass creating schemas from your collections and will not register the express route.
If you do not need GraphQL it is advised that you disable it altogether with the Payload config by setting `graphQL.disable: true`. Should you wish to enable GraphQL again, you can remove this property or set it `false`, any time. By turning it off, Payload will bypass creating schemas from your collections and will not register the route.
## Malicious File Uploads

View File

@@ -3,7 +3,7 @@ title: Querying your Documents
label: Overview
order: 10
desc: Payload provides a querying language through all APIs, allowing you to filter or search through documents within a Collection.
keywords: query, documents, overview, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: query, documents, overview, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload provides an extremely granular querying language through all APIs. Each API takes the same syntax and fully supports all options.
@@ -12,9 +12,8 @@ Payload provides an extremely granular querying language through all APIs. Each
<strong>
Here, "querying" relates to filtering or searching through documents within a Collection.
</strong>
You can build queries to pass to Find operations as well as to [restrict which documents certain
users can access](/docs/access-control/overview) via access control functions.
users can [access](/docs/access-control/overview) via access control functions.
</Banner>
## Simple queries
@@ -146,7 +145,7 @@ query {
With the REST API, you can use the full power of Payload queries as well but they become a bit more unwieldy the more complex that they get.
Simple queries are fairly straightforward to write. To understand the syntax, you need to understand how Express and similar languages would go about parsing a complex URL search string into a JSON object. For example, the above [simple query](#simple-queries) would be parsed into a string like this:
Simple queries are fairly straightforward to write. To understand the syntax, you need to understand that complex URL search strings are parsed into a JSON object. For example, the above [simple query](#simple-queries) would be parsed into a string like this:
**`https://localhost:3000/api/posts?where[color][equals]=mint`**

View File

@@ -3,7 +3,7 @@ title: Pagination
label: Pagination
order: 20
desc: Payload queries are equipped with automatic pagination so you create paginated lists of documents within your app.
keywords: query, documents, pagination, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: query, documents, pagination, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
All collection `find` queries are paginated automatically. Responses are returned with top-level meta data related to pagination, and returned documents are nested within a `docs` array.

View File

@@ -3,7 +3,7 @@ title: REST API
label: Overview
order: 10
desc: Payload generates a fully functional REST API from your Collection and Global configs.
keywords: rest, api, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: rest, api, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
@@ -578,8 +578,8 @@ Each endpoint object needs to have:
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`path`** | A string for the endpoint route after the collection or globals slug |
| **`method`** | The lowercase HTTP verb to use: 'get', 'head', 'post', 'put', 'delete', 'connect' or 'options' |
| **`handler`** | A function or array of functions to be called with **req**, **res** and **next** arguments. [Express](https://expressjs.com/en/guide/routing.html#route-handlers) |
| **`root`** | When `true`, defines the endpoint on the root Express app, bypassing Payload handlers and the `routes.api` subpath. Note: this only applies to top-level endpoints of your Payload config, endpoints defined on `collections` or `globals` cannot be root. |
| **`handler`** | A function or array of functions to be called with **req**, **res** and **next** arguments. [Next.js](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) |
| **`root`** | When `true`, defines the endpoint on the root Next.js app, bypassing Payload handlers and the `routes.api` subpath. Note: this only applies to top-level endpoints of your Payload config, endpoints defined on `collections` or `globals` cannot be root. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
Example:
@@ -618,3 +618,45 @@ export const Orders: CollectionConfig = {
**req** will have the **payload** object and can be used inside your endpoint handlers for making
calls like req.payload.find() that will make use of access control and hooks.
</Banner>
## Method Override for GET Requests
Payload supports a method override feature that allows you to send GET requests using the HTTP POST method. This can be particularly useful in scenarios when the query string in a regular GET request is too long.
### How to Use
To use this feature, include the `X-HTTP-Method-Override` header set to `GET` in your POST request. The parameters should be sent in the body of the request with the `Content-Type` set to `application/x-www-form-urlencoded`.
### Example
Here is an example of how to use the method override to perform a GET request:
#### Using Method Override (POST)
```ts
const res = await fetch(`${api}/${collectionSlug}`, {
method: 'POST',
credentials: 'include',
headers: {
'Accept-Language': i18n.language,
'Content-Type': 'application/x-www-form-urlencoded',
'X-HTTP-Method-Override': 'GET',
},
body: qs.stringify({
depth: 1,
locale: 'en',
}),
})
```
#### Equivalent Regular GET Request
```ts
const res = await fetch(`${api}/${collectionSlug}?depth=1&locale=en`, {
method: 'GET',
credentials: 'include',
headers: {
'Accept-Language': i18n.language,
},
})
```

View File

@@ -3,7 +3,7 @@ title: Troubleshooting
label: Troubleshooting
order: 10
desc: Troubleshooting Common Issues in Payload
keywords: admin, components, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, express, troubleshooting
keywords: admin, components, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, nextjs, troubleshooting
---
## Common Issues

View File

@@ -3,7 +3,7 @@ title: Generating TypeScript Interfaces
label: Generating Types
order: 20
desc: Generate your own TypeScript interfaces based on your collections and globals.
keywords: headless cms, typescript, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: headless cms, typescript, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
While building your own custom functionality into Payload, like plugins, hooks, access control functions, custom views, GraphQL queries / mutations, or anything else, you may benefit from generating your own TypeScript types dynamically from your Payload config itself.

View File

@@ -3,7 +3,7 @@ title: TypeScript - Overview
label: Overview
order: 10
desc: Payload is the most powerful TypeScript headless CMS available.
keywords: headless cms, typescript, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: headless cms, typescript, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload supports TypeScript natively, and not only that, the entirety of the CMS is built with TypeScript. To get started developing with Payload and TypeScript, you can use one of Payload's built-in boilerplates in one line via `create-payload-app`:

View File

@@ -3,7 +3,7 @@ title: Uploads
label: Overview
order: 10
desc: Payload supports uploads, storage and management of files directly on your server, combined with powerful file access control.
keywords: uploads, images, media, overview, documentation, Content Management System, cms, headless, javascript, node, react, express
keywords: uploads, images, media, overview, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
@@ -50,7 +50,7 @@ Every Payload Collection can opt-in to supporting Uploads by specifying the `upl
| **`externalFileHeaderFilter`** | Accepts existing headers and can filter/modify them. |
| **`focalPoint`** | Set to `false` to disable the focal point selection tool in the Admin panel. The focal point selector is only available when `imageSizes` or `resizeOptions` are defined. [More](#crop-and-focal-point-selector) |
| **`formatOptions`** | An object with `format` and `options` that are used with the Sharp image library to format the upload file. [More](https://sharp.pixelplumbing.com/api-output#toformat) |
| **`handlers`** | Array of Express request handlers to execute before the built-in Payload static middleware executes. |
| **`handlers`** | Array of [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) handlers to execute before the built-in Payload static middleware executes. |
| **`imageSizes`** | If specified, image uploads will be automatically resized in accordance to these image sizes. [More](#image-sizes) |
| **`mimeTypes`** | Restrict mimeTypes in the file picker. Array of valid mimetypes or mimetype wildcards [More](#mimetypes) | |
| **`resizeOptions`** | An object passed to the the Sharp image library to resize the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize) |

View File

@@ -3,7 +3,7 @@ title: Autosave
label: Autosave
order: 30
desc: Using Payload's Draft functionality, you can configure your collections and globals to autosave changes as drafts, and publish only you're ready.
keywords: version history, revisions, audit log, draft, publish, autosave, Content Management System, cms, headless, javascript, node, react, expresss
keywords: version history, revisions, audit log, draft, publish, autosave, Content Management System, cms, headless, javascript, node, react, nextjss
---
Extending on Payload's [Draft](/docs/versions/drafts) functionality, you can configure your collections and globals to autosave changes as drafts, and publish only you're ready. The Admin UI will automatically adapt to autosaving progress at an interval that you define, and will store all autosaved changes as a new Draft version. Never lose your work - and publish changes to the live document only when you're ready.

View File

@@ -3,7 +3,7 @@ title: Drafts
label: Drafts
order: 20
desc: Enable drafts on collection documents or globals and build true preview environments for your data.
keywords: version history, drafts, preview, draft, restore, publish, autosave, Content Management System, cms, headless, javascript, node, react, express
keywords: version history, drafts, preview, draft, restore, publish, autosave, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload's Draft functionality builds on top of the Versions functionality to allow you to make changes to your collection documents and globals, but publish only when you're ready. This functionality allows you to build powerful Preview environments for your data, where you can make sure your changes look good before publishing documents.
@@ -22,6 +22,7 @@ Collections and Globals both support the same options for configuring drafts. Yo
| Draft Option | Description |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `autosave` | Enable `autosave` to automatically save progress while documents are edited. To enable, set to `true` or pass an object with [options](/docs/versions/autosave). |
| `validate` | Set `validate` to `true` to validate draft documents when saved. Default is `false`. |
## Database changes

View File

@@ -3,7 +3,7 @@ title: Versions
label: Overview
order: 10
desc: Keep a version history or audit log of changes and publish collection documents and globals.
keywords: version history, revisions, audit log, draft, publish, restore, autosave, Content Management System, cms, headless, javascript, node, react, express
keywords: version history, revisions, audit log, draft, publish, restore, autosave, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>

View File

@@ -33,6 +33,7 @@ export default withBundleAnalyzer(
'.js': ['.ts', '.tsx', '.js', '.jsx'],
'.mjs': ['.mts', '.mjs'],
}
return webpackConfig
},
}),

View File

@@ -1,20 +1,24 @@
{
"name": "payload-monorepo",
"version": "3.0.0-beta.42",
"version": "3.0.0-beta.52",
"private": true,
"type": "module",
"scripts": {
"bf": "pnpm run build:force",
"build": "pnpm run build:core",
"build:all": "turbo build",
"build:app": "next build",
"build:app:analyze": "cross-env ANALYZE=true next build",
"build:clean": "pnpm clean:build",
"build:core": "turbo build --filter \"!@payloadcms/plugin-*\"",
"build:core:force": "pnpm clean:build && turbo build --filter \"!@payloadcms/plugin-*\" --no-cache --force",
"build:create-payload-app": "turbo build --filter create-payload-app",
"build:db-mongodb": "turbo build --filter db-mongodb",
"build:db-postgres": "turbo build --filter db-postgres",
"build:email-nodemailer": "turbo build --filter email-nodemailer",
"build:email-resend": "turbo build --filter email-resend",
"build:eslint-config-payload": "turbo build --filter eslint-config-payload",
"build:force": "pnpm run build:core:force",
"build:graphql": "turbo build --filter graphql",
"build:live-preview": "turbo build --filter live-preview",
"build:live-preview-react": "turbo build --filter live-preview-react",
@@ -42,21 +46,22 @@
"build:translations": "turbo build --filter translations",
"build:ui": "turbo build --filter ui",
"clean": "turbo clean",
"clean:all": "find . \\( -type d \\( -name node_modules -o -name dist -o -name .cache -o -name .next -o -name .turbo \\) -o -type f -name tsconfig.tsbuildinfo \\) -exec rm -rf {} +",
"clean:build": "find . \\( -type d \\( -name dist -o -name .cache -o -name .next -o -name .turbo \\) -o -type f -name tsconfig.tsbuildinfo \\) -not -path '*/node_modules/*' -exec rm -rf {} +",
"clean:cache": "rimraf node_modules/.cache && rimraf packages/payload/node_modules/.cache && rimraf .next",
"clean:all": "node ./scripts/delete-recursively.js '@node_modules' 'media' '**/dist' '**/.cache' '**/.next' '**/.turbo' '**/tsconfig.tsbuildinfo' '**/payload*.tgz' '**/meta_*.json'",
"clean:build": "node ./scripts/delete-recursively.js 'media' '**/dist' '**/.cache' '**/.next' '**/.turbo' '**/tsconfig.tsbuildinfo' '**/payload*.tgz' '**/meta_*.json'",
"clean:cache": "node ./scripts/delete-recursively.js node_modules/.cache! packages/payload/node_modules/.cache! .next",
"dev": "cross-env NODE_OPTIONS=--no-deprecation node ./test/dev.js",
"dev:generate-graphql-schema": "cross-env NODE_OPTIONS=--no-deprecation tsx ./test/generateGraphQLSchema.ts",
"dev:generate-types": "cross-env NODE_OPTIONS=--no-deprecation tsx ./test/generateTypes.ts",
"dev:postgres": "cross-env NODE_OPTIONS=--no-deprecation PAYLOAD_DATABASE=postgres node ./test/dev.js",
"devsafe": "rimraf .next && pnpm dev",
"devsafe": "node ./scripts/delete-recursively.js '**/.next' && pnpm dev",
"docker:restart": "pnpm docker:stop --remove-orphans && pnpm docker:start",
"docker:start": "docker compose -f packages/plugin-cloud-storage/docker-compose.yml up -d",
"docker:stop": "docker compose -f packages/plugin-cloud-storage/docker-compose.yml down",
"fix": "eslint \"packages/**/*.ts\" --fix",
"force:build": "pnpm run build:core:force",
"lint": "eslint \"packages/**/*.ts\"",
"lint-staged": "lint-staged",
"obliterate-playwright-cache": "rm -rf ~/Library/Caches/ms-playwright && find /System/Volumes/Data/private/var/folders -type d -name 'playwright*' -exec rm -rf {} +",
"obliterate-playwright-cache-macos": "rm -rf ~/Library/Caches/ms-playwright && find /System/Volumes/Data/private/var/folders -type d -name 'playwright*' -exec rm -rf {} +",
"prepare": "husky install",
"reinstall": "pnpm clean:all && pnpm install",
"release:alpha": "tsx ./scripts/release.ts --bump prerelease --tag alpha",
@@ -90,7 +95,7 @@
"@payloadcms/eslint-config": "workspace:*",
"@payloadcms/live-preview-react": "workspace:*",
"@playwright/test": "1.43.0",
"@swc/cli": "^0.1.62",
"@swc/cli": "0.3.12",
"@swc/jest": "0.2.36",
"@testing-library/jest-dom": "6.4.2",
"@testing-library/react": "14.2.1",
@@ -123,6 +128,7 @@
"husky": "^8.0.3",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"json-schema-to-typescript": "11.0.3",
"lint-staged": "^14.0.1",
"minimist": "1.2.8",
"mongodb-memory-server": "^9.0",
@@ -145,13 +151,12 @@
"slash": "3.0.0",
"sort-package-json": "^2.10.0",
"swc-plugin-transform-remove-imports": "^1.12.1",
"tempfile": "^3.0.0",
"tempy": "^1.0.1",
"ts-node": "10.9.1",
"tsx": "^4.7.1",
"turbo": "^1.13.3",
"typescript": "5.4.5",
"uuid": "^9.0.1"
"uuid": "10.0.0"
},
"peerDependencies": {
"react": "^19.0.0 || ^19.0.0-rc-f994737d14-20240522",
@@ -164,8 +169,7 @@
"pnpm": {
"allowedDeprecatedVersions": {
"abab": "2",
"domexception": "4",
"uuid": "3.4.0"
"domexception": "4"
},
"overrides": {
"@types/react": "npm:types-react@19.0.0-beta.2",

View File

@@ -1,6 +1,6 @@
{
"name": "create-payload-app",
"version": "3.0.0-beta.42",
"version": "3.0.0-beta.52",
"homepage": "https://payloadcms.com",
"repository": {
"type": "git",
@@ -40,7 +40,7 @@
],
"scripts": {
"build": "pnpm pack-template-files && pnpm typecheck && pnpm build:swc",
"build:swc": "swc ./src -d ./dist --config-file .swcrc",
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
"clean": "rimraf {dist,*.tsbuildinfo}",
"pack-template-files": "tsx src/scripts/pack-template-files.ts",
"prepublishOnly": "pnpm clean && pnpm build",

View File

@@ -5,7 +5,7 @@ import path from 'path'
import type { DbType, StorageAdapterType } from '../types.js'
import { warning } from '../utils/log.js'
import { configReplacements, dbReplacements, storageReplacements } from './replacements.js'
import { dbReplacements, storageReplacements } from './replacements.js'
/** Update payload config with necessary imports and adapters */
export async function configurePayloadConfig(args: {
@@ -15,8 +15,8 @@ export async function configurePayloadConfig(args: {
}
packageJsonName?: string
projectDirOrConfigPath: { payloadConfigPath: string } | { projectDir: string }
storageAdapter?: StorageAdapterType
sharp?: boolean
storageAdapter?: StorageAdapterType
}): Promise<void> {
if (!args.dbType) {
return
@@ -93,32 +93,32 @@ export async function configurePayloadConfig(args: {
const dbReplacement = dbReplacements[args.dbType]
configLines = replaceInConfigLines({
replacement: dbReplacement.configReplacement(args.envNames?.dbUri),
startMatch: `// database-adapter-config-start`,
endMatch: `// database-adapter-config-end`,
lines: configLines,
replacement: dbReplacement.configReplacement(args.envNames?.dbUri),
startMatch: `// database-adapter-config-start`,
})
configLines = replaceInConfigLines({
lines: configLines,
replacement: [dbReplacement.importReplacement],
startMatch: '// database-adapter-import',
lines: configLines,
})
// Storage Adapter Replacement
if (args.storageAdapter) {
const replacement = storageReplacements[args.storageAdapter]
configLines = replaceInConfigLines({
lines: configLines,
replacement: replacement.configReplacement,
startMatch: '// storage-adapter-placeholder',
lines: configLines,
})
if (replacement?.importReplacement) {
if (replacement?.importReplacement !== undefined) {
configLines = replaceInConfigLines({
lines: configLines,
replacement: [replacement.importReplacement],
startMatch: '// storage-adapter-import-placeholder',
lines: configLines,
})
}
}
@@ -126,14 +126,14 @@ export async function configurePayloadConfig(args: {
// Sharp Replacement (provided by default, only remove if explicitly set to false)
if (args.sharp === false) {
configLines = replaceInConfigLines({
lines: configLines,
replacement: [],
startMatch: 'sharp,',
lines: configLines,
})
configLines = replaceInConfigLines({
lines: configLines,
replacement: [],
startMatch: "import sharp from 'sharp'",
lines: configLines,
})
}
@@ -146,16 +146,16 @@ export async function configurePayloadConfig(args: {
}
function replaceInConfigLines({
replacement,
startMatch,
endMatch,
lines,
replacement,
startMatch,
}: {
replacement: string[]
startMatch: string
/** Optional endMatch to replace multiple lines */
endMatch?: string
lines: string[]
replacement: string[]
startMatch: string
}) {
if (!replacement) {
return lines

View File

@@ -63,12 +63,13 @@ const payloadCloudReplacement: StorageAdapterReplacement = {
// Removes placeholders
const diskReplacement: StorageAdapterReplacement = {
configReplacement: [],
importReplacement: '',
}
export const storageReplacements: Record<StorageAdapterType, StorageAdapterReplacement> = {
localDisk: diskReplacement,
payloadCloud: payloadCloudReplacement,
vercelBlobStorage: vercelBlobStorageReplacement,
localDisk: diskReplacement,
}
/**

View File

@@ -4,8 +4,7 @@ import chalk from 'chalk'
import { Syntax, parseModule } from 'esprima-next'
import fs from 'fs'
import { warning } from '../utils/log.js'
import { log } from '../utils/log.js'
import { log, warning } from '../utils/log.js'
export const withPayloadStatement = {
cjs: `const { withPayload } = require('@payloadcms/next/withPayload')\n`,

View File

@@ -77,4 +77,4 @@ export type NextAppDetails = {
export type NextConfigType = 'cjs' | 'esm'
export type StorageAdapterType = 'payloadCloud' | 'vercelBlobStorage' | 'localDisk'
export type StorageAdapterType = 'localDisk' | 'payloadCloud' | 'vercelBlobStorage'

View File

@@ -3,8 +3,7 @@ import chalk from 'chalk'
import path from 'path'
import terminalLink from 'terminal-link'
import type { ProjectTemplate } from '../types.js'
import type { PackageManager } from '../types.js'
import type { PackageManager, ProjectTemplate } from '../types.js'
import { getValidTemplates } from '../lib/templates.js'

View File

@@ -6,7 +6,7 @@
"emitDeclarationOnly": true,
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
"rootDir": "./src" /* Specify the root folder within your source files. */,
"strict": true,
"strict": true
},
"exclude": ["dist", "build", "tests", "test", "node_modules", ".eslintrc.js"],
"include": ["src/**/*.ts", "src/**/*.spec.ts", "src/**/*.tsx", "src/**/*.d.ts", "src/**/*.json"]

View File

@@ -14,7 +14,7 @@ npm install @payloadcms/db-mongodb
## Usage
```ts
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
export default buildConfig({

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