v3.60.0
payloadcms/payloadv3.60.0Oct 16, 2025by denolfe
AI Summary
This release adds multiple fallback locales, a settings menu in the admin sidebar, and enhances the multi-tenant plugin with access overrides and support for hasMany on tenant fields.
Key Highlights
- Multiple fallback locales support
- Settings menu in admin navigation sidebar
- Multi-tenant plugin access overrides
- hasMany support on tenant field
New Features
- Accept multiple locales in fallbackLocale
- Add settingsMenu to admin navigation sidebar
- Allow collection access to be overridden via callback
- Allow hasMany on tenant field overrides
- Add collection filtering to UploadFeature
- Client-side block markdown shortcuts and code blocks
Full Release Notes
## [v3.60.0](https://github.com/payloadcms/payload/compare/v3.59.1...v3.60.0) (2025-10-16)
### ๐ Features
* accept multiple locales in fallbackLocale ([#13822](https://github.com/payloadcms/payload/issues/13822)) ([623a1b8](https://github.com/payloadcms/payload/commit/623a1b8))
* adds settingsMenu to admin navigation sidebar ([#14139](https://github.com/payloadcms/payload/issues/14139)) ([ee8b3cf](https://github.com/payloadcms/payload/commit/ee8b3cf))
* **plugin-multi-tenant:** allow collection access to be overridden via callback ([#14127](https://github.com/payloadcms/payload/issues/14127)) ([c40eec2](https://github.com/payloadcms/payload/commit/c40eec2))
* **plugin-multi-tenant:** allow hasMany on tenant field overrides ([#14120](https://github.com/payloadcms/payload/issues/14120)) ([fb93cd1](https://github.com/payloadcms/payload/commit/fb93cd1))
* **plugin-multi-tenant:** user collection access overrides ([#14119](https://github.com/payloadcms/payload/issues/14119)) ([38b7a60](https://github.com/payloadcms/payload/commit/38b7a60))
* **richtext-lexical:** add collection filtering to UploadFeature, refactor relationship hooks ([#14111](https://github.com/payloadcms/payload/issues/14111)) ([6defba9](https://github.com/payloadcms/payload/commit/6defba9))
* **richtext-lexical:** client-side block markdown shortcuts, code block ([#13813](https://github.com/payloadcms/payload/issues/13813)) ([07a1eff](https://github.com/payloadcms/payload/commit/07a1eff))
**Localization**
- **Multiple fallback locales** - `fallbackLocale` now accepts an array of locales for queries and locale configs. Payload will check each locale in order until finding a value, eliminating the need for manual fallback handling. [#13822](https://github.com/payloadcms/payload/pull/13822)
```ts
/** Local API **/
await payload.findByID({
id,
collection,
locale: 'en',
fallbackLocale: ['fr', 'es'],
})
/** REST API **/
await fetch(`${baseURL}/api/${collectionSlug}?locale=en&fallbackLocale[]=fr&fallbackLocale[]=es`)
/** GraphQL **/
await restClient.GRAPHQL_POST({
body,
query: { locale: 'en', fallbackLocale: ['fr', 'es']},
})
/** Locale Configs **/
locales: [
{
code: 'en',
label: 'English',
fallbackLocale: ['fr', 'es'],
},
]
```
**Admin UI**
- **Settings menu in navigation** - New `admin.components.settingsMenu` config option adds a gear icon above the logout button. Click to open a popup menu with custom admin-level utilities and actions that don't fit into collection or global navigation. [#14139](https://github.com/payloadcms/payload/pull/14139)
<img width="174" height="239" alt="Screenshot 2025-10-14 at 11 43 37 AM" src="https://github.com/user-attachments/assets/5dca8ea7-ed99-4bc1-89c2-bc6da7d8f323" />
**Multi-Tenant Plugin**
- **Collection access overrides** - New `accessResultOverride` callback allows modifying multi-tenant access control results per operation (read, create, update, delete, readVersions, unlock). Enables custom logic like allowing shared content across tenants. [#14127](https://github.com/payloadcms/payload/pull/14127)
```ts
multiTenantPlugin<ConfigType>({
collections: {
posts: {
accessResultOverride: async ({ accessResult, accessKey, req }) => {
// here is where you can change the access result or return something entirely different
if (accessKey === 'read') {
return {
or: [
{
isShared: {
equals: true,
}
},
accessResult
]
}
} else {
return accessResult
}
}
}
}
})
```
- **Multiple tenants per document** - Tenant field overrides now support `hasMany` relationships, allowing documents to belong to multiple tenants. [#14120](https://github.com/payloadcms/payload/pull/14120)
- **User collection access overrides** - New `usersAccessResultOverride` callback enables customizing access control on the users collection, overriding default tenant privacy when needed. [#14119](https://github.com/payloadcms/payload/pull/14119)
```ts
usersAccessResultOverride: ({
accessKey: 'read', // 'create', 'read', 'update', 'delete', 'readVersions', 'unlock'
accessResult: AccessResult, // the `AccessResult` type
...args, // AccessArgs
}) => {
// this is where you could adjust what gets returned here.
if (accessKey === 'read') {
return true // over simplified example
}
// default to returning the result from the plugin
return accessResult
}
```
**Lexical Rich Text**
- **Upload collection filtering** - `UploadFeature` now supports `disabledCollections` and `enabledCollections` to control which collections appear in the upload drawer. Also refactors enabled relationships logic with cleaner `useEnabledRelationships` hook. [#14111](https://github.com/payloadcms/payload/pull/14111)
- **Client-side markdown shortcuts & code blocks** - Blocks with `admin.jsx` now support markdown shortcuts on the client (previously server-only). Includes pre-made `CodeBlock` component for use in `BlocksFeature`. Also fixes `readOnly` handling across nested fields. [#13813](https://github.com/payloadcms/payload/pull/13813)
<https://github.com/user-attachments/assets/cfc0d2a8-ffb3-4926-b097-ad9c2b133586>
### ๐ Bug Fixes
* `findDistinct` by explicit ID paths in relationships and virtual fields ([#14215](https://github.com/payloadcms/payload/issues/14215)) ([2b1b6ee](https://github.com/payloadcms/payload/commit/2b1b6ee))
* hasMany / polymorphic relationships to custom number IDs ([#14201](https://github.com/payloadcms/payload/issues/14201)) ([a3b3865](https://github.com/payloadcms/payload/commit/a3b3865))
* hide fields with read: false in list view columns, filters, and groupBy ([#14118](https://github.com/payloadcms/payload/issues/14118)) ([bcd40b6](https://github.com/payloadcms/payload/commit/bcd40b6))
* validate Point Field to -180 to 180 for longitude and -90 to 90 for latitude ([#14206](https://github.com/payloadcms/payload/issues/14206)) ([13a1d90](https://github.com/payloadcms/payload/commit/13a1d90))
* urls in upload sizes are not encoded ([#14205](https://github.com/payloadcms/payload/issues/14205)) ([747a049](https://github.com/payloadcms/payload/commit/747a049))
* restoring trashed drafts with empty required fields fails validation ([#14186](https://github.com/payloadcms/payload/issues/14186)) ([3317207](https://github.com/payloadcms/payload/commit/3317207))
* **db-d1-sqlite:** add missing `blocksAsJSON` property ([#14103](https://github.com/payloadcms/payload/issues/14103)) ([f14a38e](https://github.com/payloadcms/payload/commit/f14a38e))
* **db-mongodb:** documents not showing in folders with `useJoinAggregations: false` ([#14155](https://github.com/payloadcms/payload/issues/14155)) ([e613a78](https://github.com/payloadcms/payload/commit/e613a78))
* **db-mongodb:** improve check for `ObjectId` ([#14131](https://github.com/payloadcms/payload/issues/14131)) ([32e2be1](https://github.com/payloadcms/payload/commit/32e2be1))
* **graphql:** bump tsx version to get around esbuild vulnerability ([#14207](https://github.com/payloadcms/payload/issues/14207)) ([d7ec48f](https://github.com/payloadcms/payload/commit/d7ec48f))
* **next:** custom views not overriding built-in single-segment routes ([#14066](https://github.com/payloadcms/payload/issues/14066)) ([691f810](https://github.com/payloadcms/payload/commit/691f810))
* **plugin-multi-tenant:** object reference mutations in addFilterOptionsToFields ([#14150](https://github.com/payloadcms/payload/issues/14150)) ([e62f1fe](https://github.com/payloadcms/payload/commit/e62f1fe))
* **richtext-lexical:** state key collisions when multiple TextStateFeatures are registered ([#14194](https://github.com/payloadcms/payload/issues/14194)) ([f01a6ed](https://github.com/payloadcms/payload/commit/f01a6ed))
* **richtext-lexical:** editor throws an error if OrderedList is registered but not UnorderedList or CheckList ([#14149](https://github.com/payloadcms/payload/issues/14149)) ([1fe75e0](https://github.com/payloadcms/payload/commit/1fe75e0))
* **richtext-lexical:** editing a copied inline block also modifies the original ([#14137](https://github.com/payloadcms/payload/issues/14137)) ([5bacb38](https://github.com/payloadcms/payload/commit/5bacb38))
* **richtext-lexical:** correctly type field property of RenderLexical ([#14141](https://github.com/payloadcms/payload/issues/14141)) ([cd94f8e](https://github.com/payloadcms/payload/commit/cd94f8e))
* **richtext-lexical:** improve type autocomplete and assignability for lexical nodes ([#14112](https://github.com/payloadcms/payload/issues/14112)) ([a46faf1](https://github.com/payloadcms/payload/commit/a46faf1))
* **sdk:** `pagination` is not passed to search params ([#14126](https://github.com/payloadcms/payload/issues/14126)) ([ee9f160](https://github.com/payloadcms/payload/commit/ee9f160))
* **storage-gcs:** bump @google-cloud/storage for vulnerability ([#14199](https://github.com/payloadcms/payload/issues/14199)) ([1077aa7](https://github.com/payloadcms/payload/commit/1077aa7))
* **storage-r2:** uploads with prefix don't work, add `test/storage-r2` ([#14132](https://github.com/payloadcms/payload/issues/14132)) ([4fd4cb0](https://github.com/payloadcms/payload/commit/4fd4cb0))
* **templates:** encoding and decoding slugs in website template ([#14216](https://github.com/payloadcms/payload/issues/14216)) ([cacf523](https://github.com/payloadcms/payload/commit/cacf523))
* **templates:** ecommerce seeding issue ([#14196](https://github.com/payloadcms/payload/issues/14196)) ([d65b8c6](https://github.com/payloadcms/payload/commit/d65b8c6))
### ๐ Refactors
* **richtext-lexical:** add jsdoc to deprecated HTMLConverterFeature ([#14193](https://github.com/payloadcms/payload/issues/14193)) ([0b718bd](https://github.com/payloadcms/payload/commit/0b718bd))
### ๐ Documentation
* revert sentry docs change ([#14113](https://github.com/payloadcms/payload/issues/14113)) ([8844eaf](https://github.com/payloadcms/payload/commit/8844eaf))
* incorrect pg driver injection example in Sentry integration docs ([#14088](https://github.com/payloadcms/payload/issues/14088)) ([95dbaed](https://github.com/payloadcms/payload/commit/95dbaed))
### ๐งช Tests
* allows running Jest tests through Test Explorer in VSCode and other improvements ([#13751](https://github.com/payloadcms/payload/issues/13751)) ([0d92a43](https://github.com/payloadcms/payload/commit/0d92a43))
### โ๏ธ CI
* notify website repo on release [skip ci] ([#14140](https://github.com/payloadcms/payload/issues/14140)) ([a36e5d2](https://github.com/payloadcms/payload/commit/a36e5d2))
* add website dispatch event, testing for releases [skip ci] ([#14138](https://github.com/payloadcms/payload/issues/14138)) ([b0d31ba](https://github.com/payloadcms/payload/commit/b0d31ba))
* add missing labels to bug report template [skip ci] ([#14134](https://github.com/payloadcms/payload/issues/14134)) ([3069e5b](https://github.com/payloadcms/payload/commit/3069e5b))
* update generate-template-variations script to cover cloudflare template ([#14105](https://github.com/payloadcms/payload/issues/14105)) ([e78057b](https://github.com/payloadcms/payload/commit/e78057b))
### ๐ก Chores
* better audit dependencies script ([#14189](https://github.com/payloadcms/payload/issues/14189)) ([f9e75a4](https://github.com/payloadcms/payload/commit/f9e75a4))
* ignore agent local files [skip ci] ([#14184](https://github.com/payloadcms/payload/issues/14184)) ([7ecb5a0](https://github.com/payloadcms/payload/commit/7ecb5a0))
* **drizzle:** bump drizzle-orm and drizzle-kit for vulnerabilities ([#14200](https://github.com/payloadcms/payload/issues/14200)) ([4afa286](https://github.com/payloadcms/payload/commit/4afa286))
* **email-nodemailer:** bump nodemailer dependencies to latest ([#14121](https://github.com/payloadcms/payload/issues/14121)) ([077c6f5](https://github.com/payloadcms/payload/commit/077c6f5))
### ๐ค Contributors
- Sasha (@r1tsuu)
- Patrik (@PatrikKozak)
- Paul (@paulpopus)
- Jessica Rynkar (@jessrynkar)
- German Jablonski (@GermanJablo)
- Elliot DeNolf (@denolfe)
- Elliott W (@elliott-w)
- Jarrod Flesch (@JarrodMFlesch)
- Alessio Gravili (@AlessioGr)
- Diogo Gaspar (@shadowoff09)