diff --git a/templates/website/src/app/(payload)/admin/[[...segments]]/not-found.tsx b/templates/website/src/app/(payload)/admin/[[...segments]]/not-found.tsx
new file mode 100644
index 000000000..e7723f49a
--- /dev/null
+++ b/templates/website/src/app/(payload)/admin/[[...segments]]/not-found.tsx
@@ -0,0 +1,22 @@
+/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
+import type { Metadata } from 'next'
+
+import config from '@payload-config'
+/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
+import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views'
+
+type Args = {
+ params: {
+ segments: string[]
+ }
+ searchParams: {
+ [key: string]: string | string[]
+ }
+}
+
+export const generateMetadata = ({ params, searchParams }: Args): Promise
=>
+ generatePageMetadata({ config, params, searchParams })
+
+const NotFound = ({ params, searchParams }: Args) => NotFoundPage({ config, params, searchParams })
+
+export default NotFound
diff --git a/templates/website/src/app/(payload)/admin/[[...segments]]/page.tsx b/templates/website/src/app/(payload)/admin/[[...segments]]/page.tsx
index 6dd436af4..61be15c88 100644
--- a/templates/website/src/app/(payload)/admin/[[...segments]]/page.tsx
+++ b/templates/website/src/app/(payload)/admin/[[...segments]]/page.tsx
@@ -1,7 +1,9 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
+import type { Metadata } from 'next'
+
import config from '@payload-config'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
-import { RootPage } from '@payloadcms/next/views'
+import { RootPage, generatePageMetadata } from '@payloadcms/next/views'
type Args = {
params: {
@@ -12,6 +14,9 @@ type Args = {
}
}
+export const generateMetadata = ({ params, searchParams }: Args): Promise =>
+ generatePageMetadata({ config, params, searchParams })
+
const Page = ({ params, searchParams }: Args) => RootPage({ config, params, searchParams })
export default Page
diff --git a/templates/website/src/app/(payload)/api/[...slug]/route.ts b/templates/website/src/app/(payload)/api/[...slug]/route.ts
index 282e1ad32..52caec96a 100644
--- a/templates/website/src/app/(payload)/api/[...slug]/route.ts
+++ b/templates/website/src/app/(payload)/api/[...slug]/route.ts
@@ -1,9 +1,10 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import config from '@payload-config'
-import { REST_DELETE, REST_GET, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
+import { REST_DELETE, REST_GET, REST_OPTIONS, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
export const GET = REST_GET(config)
export const POST = REST_POST(config)
export const DELETE = REST_DELETE(config)
export const PATCH = REST_PATCH(config)
+export const OPTIONS = REST_OPTIONS(config)
diff --git a/templates/website/src/app/components/PayloadRedirects/index.tsx b/templates/website/src/app/components/PayloadRedirects/index.tsx
index 7fbeac42f..022e4b695 100644
--- a/templates/website/src/app/components/PayloadRedirects/index.tsx
+++ b/templates/website/src/app/components/PayloadRedirects/index.tsx
@@ -2,18 +2,21 @@ import type React from 'react'
import type { Page, Post } from 'src/payload-types'
import { getCachedDocument } from '@/utilities/getDocument'
-import { getCachedRedirect } from '@/utilities/getRedirect'
+import { getCachedRedirects } from '@/utilities/getRedirects'
import { notFound, redirect } from 'next/navigation'
interface Props {
+ disableNotFound?: boolean
url: string
}
/* This component helps us with SSR based dynamic redirects */
-export const PayloadRedirects: React.FC = async ({ url }) => {
+export const PayloadRedirects: React.FC = async ({ disableNotFound, url }) => {
const slug = url.startsWith('/') ? url : `${url}`
- const redirectItem = await getCachedRedirect(slug)()
+ const redirects = await getCachedRedirects()()
+
+ const redirectItem = redirects.find((redirect) => redirect.from === slug)
if (redirectItem) {
if (redirectItem.to?.url) {
@@ -39,5 +42,6 @@ export const PayloadRedirects: React.FC = async ({ url }) => {
if (redirectUrl) redirect(redirectUrl)
}
+ if (disableNotFound) return null
return notFound()
}
diff --git a/templates/website/src/app/next/revalidate/route.ts b/templates/website/src/app/next/revalidate/route.ts
deleted file mode 100644
index 6b2a39536..000000000
--- a/templates/website/src/app/next/revalidate/route.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import type { NextRequest } from 'next/server'
-
-import { revalidatePath, revalidateTag } from 'next/cache'
-import { NextResponse } from 'next/server'
-
-export type RevalidationType = 'path' | 'tag'
-
-// eslint-disable-next-line @typescript-eslint/require-await
-export async function GET(request: NextRequest): Promise {
- const path = request.nextUrl.searchParams.get('path')
- const secret = request.nextUrl.searchParams.get('secret')
- const tag = request.nextUrl.searchParams.get('tag')
- const type: RevalidationType =
- (request.nextUrl.searchParams.get('type') as RevalidationType) ?? 'path'
-
- if (!secret || secret !== process.env.NEXT_PRIVATE_REVALIDATION_KEY) {
- // Do not indicate that the revalidation key is incorrect in the response
- // This will protect this API route from being exploited
- return new Response('Invalid request', { status: 400 })
- }
-
- if ((type === 'path' && !path) || (type === 'tag' && !tag)) {
- return new Response('Invalid request', { status: 400 })
- }
-
- if (type === 'path') {
- revalidatePath(path)
- return NextResponse.json({ now: Date.now(), revalidated: true })
- }
-
- if (type === 'tag') {
- revalidateTag(tag)
- return NextResponse.json({ now: Date.now(), revalidated: true })
- }
-
- return NextResponse.json({ now: Date.now(), revalidated: false })
-}
diff --git a/templates/website/src/app/utilities/generateMeta.ts b/templates/website/src/app/utilities/generateMeta.ts
index e32183359..46eec753e 100644
--- a/templates/website/src/app/utilities/generateMeta.ts
+++ b/templates/website/src/app/utilities/generateMeta.ts
@@ -14,6 +14,8 @@ export const generateMeta = async (args: { doc: Page | Post }): Promise
- unstable_cache(async () => getRedirect(slug), [slug], {
- tags: [`redirects_${slug}`],
+export const getCachedRedirects = () =>
+ unstable_cache(async () => getRedirects(), ['redirects'], {
+ tags: ['redirects'],
})
diff --git a/templates/website/src/app/utilities/mergeOpenGraph.ts b/templates/website/src/app/utilities/mergeOpenGraph.ts
index 9e3a6caf9..9580f134b 100644
--- a/templates/website/src/app/utilities/mergeOpenGraph.ts
+++ b/templates/website/src/app/utilities/mergeOpenGraph.ts
@@ -5,7 +5,9 @@ const defaultOpenGraph: Metadata['openGraph'] = {
description: 'An open-source website built with Payload and Next.js.',
images: [
{
- url: 'https://payloadcms.com/images/og-image.jpg',
+ url: process.env.NEXT_PUBLIC_SERVER_URL
+ ? `${process.env.NEXT_PUBLIC_SERVER_URL}/website-template-OG.webp`
+ : '/website-template-OG.webp',
},
],
siteName: 'Payload Website Template',
diff --git a/templates/website/src/dotenv.js b/templates/website/src/dotenv.js
deleted file mode 100644
index 8c62a1a29..000000000
--- a/templates/website/src/dotenv.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = {
- config: () => null,
-}
diff --git a/templates/website/src/emptyModuleMock.js b/templates/website/src/emptyModuleMock.js
deleted file mode 100644
index 08bee4468..000000000
--- a/templates/website/src/emptyModuleMock.js
+++ /dev/null
@@ -1,4 +0,0 @@
-module.exports = {
- raw: () => {},
- url: () => {},
-}
diff --git a/templates/website/src/payload-types.ts b/templates/website/src/payload-types.ts
index 2f57738d2..53ad1adcf 100644
--- a/templates/website/src/payload-types.ts
+++ b/templates/website/src/payload-types.ts
@@ -7,6 +7,9 @@
*/
export interface Config {
+ auth: {
+ users: UserAuthOperations;
+ };
collections: {
pages: Page;
posts: Post;
@@ -28,6 +31,19 @@ export interface Config {
collection: 'users';
};
}
+export interface UserAuthOperations {
+ forgotPassword: {
+ email: string;
+ };
+ login: {
+ password: string;
+ email: string;
+ };
+ registerFirstUser: {
+ email: string;
+ password: string;
+ };
+}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "pages".
@@ -318,7 +334,6 @@ export interface Post {
export interface User {
id: string;
name?: string | null;
- roles?: ('admin' | 'user')[] | null;
updatedAt: string;
createdAt: string;
email: string;
@@ -641,6 +656,13 @@ export interface BannerBlock {
blockName?: string | null;
blockType: 'banner';
}
+/**
+ * This interface was referenced by `Config`'s JSON-Schema
+ * via the `definition` "auth".
+ */
+export interface Auth {
+ [k: string]: unknown;
+}
declare module 'payload' {
diff --git a/templates/website/src/payload.config.ts b/templates/website/src/payload.config.ts
index aee071795..2524db56c 100644
--- a/templates/website/src/payload.config.ts
+++ b/templates/website/src/payload.config.ts
@@ -17,8 +17,7 @@ import { ItalicFeature } from '@payloadcms/richtext-lexical'
import { BoldFeature } from '@payloadcms/richtext-lexical'
import dotenv from 'dotenv'
import path from 'path'
-import { buildConfig } from 'payload/config'
-import { revalidateRedirect } from 'src/payload/hooks/revalidateRedirect'
+import { buildConfig } from 'payload'
import { fileURLToPath } from 'url'
import Categories from './payload/collections/Categories'
@@ -31,6 +30,7 @@ import BeforeLogin from './payload/components/BeforeLogin'
import { seed } from './payload/endpoints/seed'
import { Footer } from './payload/globals/Footer/Footer'
import { Header } from './payload/globals/Header/Header'
+import { revalidateRedirects } from './payload/hooks/revalidateRedirects'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
@@ -109,8 +109,22 @@ export default buildConfig({
redirectsPlugin({
collections: ['pages', 'posts'],
overrides: {
+ // @ts-expect-error
+ fields: ({ defaultFields }) => {
+ return defaultFields.map((field) => {
+ if ('name' in field && field.name === 'from') {
+ return {
+ ...field,
+ admin: {
+ description: 'You will need to rebuild the website when changing this field.',
+ },
+ }
+ }
+ return field
+ })
+ },
hooks: {
- afterChange: [revalidateRedirect],
+ afterChange: [revalidateRedirects],
},
},
}),
diff --git a/templates/website/src/payload/access/admins.ts b/templates/website/src/payload/access/admins.ts
deleted file mode 100644
index 44f2b8326..000000000
--- a/templates/website/src/payload/access/admins.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import type { AccessArgs } from 'payload/config'
-
-import type { User } from '../../payload-types'
-
-import { checkRole } from '../collections/Users/checkRole'
-
-type isAdmin = (args: AccessArgs) => boolean
-
-export const admins: isAdmin = ({ req: { user } }) => {
- return checkRole(['admin'], user)
-}
diff --git a/templates/website/src/payload/access/anyone.ts b/templates/website/src/payload/access/anyone.ts
index c09860033..bf37c3a11 100644
--- a/templates/website/src/payload/access/anyone.ts
+++ b/templates/website/src/payload/access/anyone.ts
@@ -1,3 +1,3 @@
-import type { Access } from 'payload/config'
+import type { Access } from 'payload'
export const anyone: Access = () => true
diff --git a/templates/website/src/payload/access/authenticated.ts b/templates/website/src/payload/access/authenticated.ts
new file mode 100644
index 000000000..e7f0ffa80
--- /dev/null
+++ b/templates/website/src/payload/access/authenticated.ts
@@ -0,0 +1,11 @@
+import type { AccessArgs } from 'payload'
+
+import type { User } from '../../payload-types'
+
+type isAuthenticated = (args: AccessArgs) => boolean
+
+export const authenticated: isAuthenticated = ({ req: { user } }) => {
+ if (user) {
+ return true
+ }
+}
diff --git a/templates/website/src/payload/access/authenticatedOrPublished.ts b/templates/website/src/payload/access/authenticatedOrPublished.ts
new file mode 100644
index 000000000..e49198fba
--- /dev/null
+++ b/templates/website/src/payload/access/authenticatedOrPublished.ts
@@ -0,0 +1,13 @@
+import type { Access } from 'payload'
+
+export const authenticatedOrPublished: Access = ({ req: { user } }) => {
+ if (user) {
+ return true
+ }
+
+ return {
+ _status: {
+ equals: 'published',
+ },
+ }
+}
diff --git a/templates/website/src/payload/access/usersOrPublished.ts b/templates/website/src/payload/access/usersOrPublished.ts
deleted file mode 100644
index bc6e6ce75..000000000
--- a/templates/website/src/payload/access/usersOrPublished.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import type { Access } from 'payload/config'
-
-export const usersOrPublished: Access = ({ req: { user } }) => {
- if (user) {
- return true
- }
-
- return {
- _status: {
- equals: 'published',
- },
- }
-}
diff --git a/templates/website/src/payload/blocks/ArchiveBlock/index.ts b/templates/website/src/payload/blocks/ArchiveBlock/index.ts
index 972a65102..444c5d0c6 100644
--- a/templates/website/src/payload/blocks/ArchiveBlock/index.ts
+++ b/templates/website/src/payload/blocks/ArchiveBlock/index.ts
@@ -1,4 +1,4 @@
-import type { Block } from 'payload/types'
+import type { Block } from 'payload'
import {
FixedToolbarFeature,
diff --git a/templates/website/src/payload/blocks/Banner/index.ts b/templates/website/src/payload/blocks/Banner/index.ts
index 233fe7dff..53e46b5cb 100644
--- a/templates/website/src/payload/blocks/Banner/index.ts
+++ b/templates/website/src/payload/blocks/Banner/index.ts
@@ -1,4 +1,4 @@
-import type { Block } from 'payload/types'
+import type { Block } from 'payload'
import {
FixedToolbarFeature,
diff --git a/templates/website/src/payload/blocks/CallToAction/index.ts b/templates/website/src/payload/blocks/CallToAction/index.ts
index 31d3883dd..667f425c8 100644
--- a/templates/website/src/payload/blocks/CallToAction/index.ts
+++ b/templates/website/src/payload/blocks/CallToAction/index.ts
@@ -1,4 +1,4 @@
-import type { Block } from 'payload/types'
+import type { Block } from 'payload'
import {
FixedToolbarFeature,
diff --git a/templates/website/src/payload/blocks/Code/index.ts b/templates/website/src/payload/blocks/Code/index.ts
index 4324b4d26..10d8cef13 100644
--- a/templates/website/src/payload/blocks/Code/index.ts
+++ b/templates/website/src/payload/blocks/Code/index.ts
@@ -1,4 +1,4 @@
-import type { Block } from 'payload/types'
+import type { Block } from 'payload'
export const Code: Block = {
slug: 'code',
diff --git a/templates/website/src/payload/blocks/Content/index.ts b/templates/website/src/payload/blocks/Content/index.ts
index 6a2ce4115..11e14e61e 100644
--- a/templates/website/src/payload/blocks/Content/index.ts
+++ b/templates/website/src/payload/blocks/Content/index.ts
@@ -1,4 +1,4 @@
-import type { Block, Field } from 'payload/types'
+import type { Block, Field } from 'payload'
import {
FixedToolbarFeature,
diff --git a/templates/website/src/payload/blocks/Form/index.ts b/templates/website/src/payload/blocks/Form/index.ts
index 27435bc5b..9b4399538 100644
--- a/templates/website/src/payload/blocks/Form/index.ts
+++ b/templates/website/src/payload/blocks/Form/index.ts
@@ -1,4 +1,4 @@
-import type { Block } from 'payload/types'
+import type { Block } from 'payload'
import {
FixedToolbarFeature,
diff --git a/templates/website/src/payload/blocks/MediaBlock/index.ts b/templates/website/src/payload/blocks/MediaBlock/index.ts
index a9351c479..35b6d9498 100644
--- a/templates/website/src/payload/blocks/MediaBlock/index.ts
+++ b/templates/website/src/payload/blocks/MediaBlock/index.ts
@@ -1,4 +1,4 @@
-import type { Block } from 'payload/types'
+import type { Block } from 'payload'
export const MediaBlock: Block = {
slug: 'mediaBlock',
diff --git a/templates/website/src/payload/collections/Categories.ts b/templates/website/src/payload/collections/Categories.ts
index 693612173..70ba7f97b 100644
--- a/templates/website/src/payload/collections/Categories.ts
+++ b/templates/website/src/payload/collections/Categories.ts
@@ -1,9 +1,15 @@
-import type { CollectionConfig } from 'payload/types'
+import type { CollectionConfig } from 'payload'
+
+import { anyone } from '../access/anyone'
+import { authenticated } from '../access/authenticated'
const Categories: CollectionConfig = {
slug: 'categories',
access: {
- read: () => true,
+ create: authenticated,
+ delete: authenticated,
+ read: anyone,
+ update: authenticated,
},
admin: {
useAsTitle: 'title',
diff --git a/templates/website/src/payload/collections/Media.ts b/templates/website/src/payload/collections/Media.ts
index 92e91cfa7..e8037f243 100644
--- a/templates/website/src/payload/collections/Media.ts
+++ b/templates/website/src/payload/collections/Media.ts
@@ -1,4 +1,4 @@
-import type { CollectionConfig } from 'payload/types'
+import type { CollectionConfig } from 'payload'
import {
FixedToolbarFeature,
@@ -8,13 +8,19 @@ import {
import path from 'path'
import { fileURLToPath } from 'url'
+import { anyone } from '../access/anyone'
+import { authenticated } from '../access/authenticated'
+
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
export const Media: CollectionConfig = {
slug: 'media',
access: {
- read: () => true,
+ create: authenticated,
+ delete: authenticated,
+ read: anyone,
+ update: authenticated,
},
fields: [
{
diff --git a/templates/website/src/payload/collections/Pages/hooks/revalidatePage.ts b/templates/website/src/payload/collections/Pages/hooks/revalidatePage.ts
index 50e53c9ec..f1b5e3515 100644
--- a/templates/website/src/payload/collections/Pages/hooks/revalidatePage.ts
+++ b/templates/website/src/payload/collections/Pages/hooks/revalidatePage.ts
@@ -1,13 +1,29 @@
-import type { CollectionAfterChangeHook } from 'payload/types'
+import type { CollectionAfterChangeHook } from 'payload'
+
+import { revalidatePath } from 'next/cache'
import type { Page } from '../../../../payload-types'
-import { revalidate } from '../../../utilities/revalidate'
-
-export const revalidatePage: CollectionAfterChangeHook = ({ doc, req: { payload } }) => {
+export const revalidatePage: CollectionAfterChangeHook = ({
+ doc,
+ previousDoc,
+ req: { payload },
+}) => {
if (doc._status === 'published') {
const path = doc.slug === 'home' ? '/' : `/${doc.slug}`
- void revalidate({ collection: 'pages', path, payload })
+
+ payload.logger.info(`Revalidating page at path: ${path}`)
+
+ revalidatePath(path)
+ }
+
+ // If the page was previously published, we need to revalidate the old path
+ if (previousDoc?._status === 'published' && doc._status !== 'published') {
+ const oldPath = previousDoc.slug === 'home' ? '/' : `/${previousDoc.slug}`
+
+ payload.logger.info(`Revalidating old page at path: ${oldPath}`)
+
+ revalidatePath(oldPath)
}
return doc
diff --git a/templates/website/src/payload/collections/Pages/index.ts b/templates/website/src/payload/collections/Pages/index.ts
index be50efb5e..1cdb619c2 100644
--- a/templates/website/src/payload/collections/Pages/index.ts
+++ b/templates/website/src/payload/collections/Pages/index.ts
@@ -1,7 +1,7 @@
-import type { CollectionConfig } from 'payload/types'
+import type { CollectionConfig } from 'payload'
-import { admins } from '../../access/admins'
-import { usersOrPublished } from '../../access/usersOrPublished'
+import { authenticated } from '../../access/authenticated'
+import { authenticatedOrPublished } from '../../access/authenticatedOrPublished'
import { Archive } from '../../blocks/ArchiveBlock'
import { CallToAction } from '../../blocks/CallToAction'
import { Content } from '../../blocks/Content'
@@ -16,10 +16,10 @@ import { revalidatePage } from './hooks/revalidatePage'
export const Pages: CollectionConfig = {
slug: 'pages',
access: {
- create: admins,
- delete: admins,
- read: usersOrPublished,
- update: admins,
+ create: authenticated,
+ delete: authenticated,
+ read: authenticatedOrPublished,
+ update: authenticated,
},
admin: {
defaultColumns: ['title', 'slug', 'updatedAt'],
diff --git a/templates/website/src/payload/collections/Posts/hooks/populateAuthors.ts b/templates/website/src/payload/collections/Posts/hooks/populateAuthors.ts
index 3d35160f5..7c8d46cf4 100644
--- a/templates/website/src/payload/collections/Posts/hooks/populateAuthors.ts
+++ b/templates/website/src/payload/collections/Posts/hooks/populateAuthors.ts
@@ -1,4 +1,4 @@
-import type { CollectionAfterReadHook } from 'payload/types'
+import type { CollectionAfterReadHook } from 'payload'
// The `user` collection has access control locked so that users are not publicly accessible
// This means that we need to populate the authors manually here to protect user privacy
diff --git a/templates/website/src/payload/collections/Posts/hooks/revalidatePost.ts b/templates/website/src/payload/collections/Posts/hooks/revalidatePost.ts
index 27e129f7d..40eefb7a2 100644
--- a/templates/website/src/payload/collections/Posts/hooks/revalidatePost.ts
+++ b/templates/website/src/payload/collections/Posts/hooks/revalidatePost.ts
@@ -1,12 +1,29 @@
-import type { CollectionAfterChangeHook } from 'payload/types'
+import type { CollectionAfterChangeHook } from 'payload'
+
+import { revalidatePath } from 'next/cache'
import type { Post } from '../../../../payload-types'
-import { revalidate } from '../../../utilities/revalidate'
-
-export const revalidatePost: CollectionAfterChangeHook = ({ doc, req: { payload } }) => {
+export const revalidatePost: CollectionAfterChangeHook = ({
+ doc,
+ previousDoc,
+ req: { payload },
+}) => {
if (doc._status === 'published') {
- void revalidate({ collection: 'posts', path: `/posts/${doc.slug}`, payload })
+ const path = `/posts/${doc.slug}`
+
+ payload.logger.info(`Revalidating post at path: ${path}`)
+
+ revalidatePath(path)
+ }
+
+ // If the post was previously published, we need to revalidate the old path
+ if (previousDoc._status === 'published' && doc._status !== 'published') {
+ const oldPath = `/posts/${previousDoc.slug}`
+
+ payload.logger.info(`Revalidating old post at path: ${oldPath}`)
+
+ revalidatePath(oldPath)
}
return doc
diff --git a/templates/website/src/payload/collections/Posts/index.ts b/templates/website/src/payload/collections/Posts/index.ts
index a90bb93e3..c5d4b7e8d 100644
--- a/templates/website/src/payload/collections/Posts/index.ts
+++ b/templates/website/src/payload/collections/Posts/index.ts
@@ -1,4 +1,4 @@
-import type { CollectionConfig } from 'payload/types'
+import type { CollectionConfig } from 'payload'
import {
FixedToolbarFeature,
@@ -9,8 +9,8 @@ import {
} from '@payloadcms/richtext-lexical'
import { BlocksFeature } from '@payloadcms/richtext-lexical'
-import { admins } from '../../access/admins'
-import { usersOrPublished } from '../../access/usersOrPublished'
+import { authenticated } from '../../access/authenticated'
+import { authenticatedOrPublished } from '../../access/authenticatedOrPublished'
import { Banner } from '../../blocks/Banner'
import { Code } from '../../blocks/Code'
import { MediaBlock } from '../../blocks/MediaBlock'
@@ -22,10 +22,10 @@ import { revalidatePost } from './hooks/revalidatePost'
export const Posts: CollectionConfig = {
slug: 'posts',
access: {
- create: admins,
- delete: admins,
- read: usersOrPublished,
- update: admins,
+ create: authenticated,
+ delete: authenticated,
+ read: authenticatedOrPublished,
+ update: authenticated,
},
admin: {
defaultColumns: ['title', 'slug', 'updatedAt'],
diff --git a/templates/website/src/payload/collections/Users/access/adminsAndUser.ts b/templates/website/src/payload/collections/Users/access/adminsAndUser.ts
deleted file mode 100644
index 17630ce19..000000000
--- a/templates/website/src/payload/collections/Users/access/adminsAndUser.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { Access } from 'payload/types'
-
-import { checkRole } from '../checkRole'
-
-const adminsAndUser: Access = ({ req: { user } }) => {
- if (user) {
- if (checkRole(['admin'], user)) {
- return true
- }
-
- return {
- id: {
- equals: user.id,
- },
- }
- }
-
- return false
-}
-
-export default adminsAndUser
diff --git a/templates/website/src/payload/collections/Users/checkRole.ts b/templates/website/src/payload/collections/Users/checkRole.ts
deleted file mode 100644
index 83aa21a1c..000000000
--- a/templates/website/src/payload/collections/Users/checkRole.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { User } from '../../../payload-types'
-
-export const checkRole = (allRoles: User['roles'] = [], user?: User): boolean => {
- if (user) {
- if (
- allRoles.some((role) => {
- return user?.roles?.some((individualRole) => {
- return individualRole === role
- })
- })
- )
- return true
- }
-
- return false
-}
diff --git a/templates/website/src/payload/collections/Users/hooks/ensureFirstUserIsAdmin.ts b/templates/website/src/payload/collections/Users/hooks/ensureFirstUserIsAdmin.ts
deleted file mode 100644
index b953ae2c7..000000000
--- a/templates/website/src/payload/collections/Users/hooks/ensureFirstUserIsAdmin.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import type { FieldHook } from 'payload/types'
-
-import type { User } from '../../../../payload-types'
-
-// ensure the first user created is an admin
-// 1. lookup a single user on create as succinctly as possible
-// 2. if there are no users found, append `admin` to the roles array
-// access control is already handled by this fields `access` property
-// it ensures that only admins can create and update the `roles` field
-export const ensureFirstUserIsAdmin: FieldHook = async ({ operation, req, value }) => {
- if (operation === 'create') {
- const users = await req.payload.find({ collection: 'users', depth: 0, limit: 0 })
- if (users.totalDocs === 0) {
- // if `admin` not in array of values, add it
- if (!(value || []).includes('admin')) {
- return [...(value || []), 'admin']
- }
- }
- }
-
- return value
-}
diff --git a/templates/website/src/payload/collections/Users/hooks/loginAfterCreate.ts b/templates/website/src/payload/collections/Users/hooks/loginAfterCreate.ts
deleted file mode 100644
index c915aacb8..000000000
--- a/templates/website/src/payload/collections/Users/hooks/loginAfterCreate.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import type { CollectionAfterChangeHook } from 'payload/types'
-
-export const loginAfterCreate: CollectionAfterChangeHook = async ({
- doc,
- operation,
- req,
- req: {
- data = {
- email: '',
- password: '',
- },
- payload,
- user = null,
- },
-}) => {
- if (operation === 'create' && !user) {
- const { email, password } = data
-
- if (email && typeof email === 'string' && password && typeof password === 'string') {
- const { token, user } = await payload.login({
- collection: 'users',
- data: { email, password },
- req,
- })
-
- return {
- ...doc,
- token,
- user,
- }
- }
- }
-
- return doc
-}
diff --git a/templates/website/src/payload/collections/Users/index.ts b/templates/website/src/payload/collections/Users/index.ts
index fb02315a5..98287c9fd 100644
--- a/templates/website/src/payload/collections/Users/index.ts
+++ b/templates/website/src/payload/collections/Users/index.ts
@@ -1,20 +1,15 @@
-import type { CollectionConfig } from 'payload/types'
+import type { CollectionConfig } from 'payload'
-import { admins } from '../../access/admins'
-import { anyone } from '../../access/anyone'
-import adminsAndUser from './access/adminsAndUser'
-import { checkRole } from './checkRole'
-import { ensureFirstUserIsAdmin } from './hooks/ensureFirstUserIsAdmin'
-import { loginAfterCreate } from './hooks/loginAfterCreate'
+import { authenticated } from '../../access/authenticated'
const Users: CollectionConfig = {
slug: 'users',
access: {
- admin: ({ req: { user } }) => checkRole(['admin'], user),
- create: anyone,
- delete: admins,
- read: adminsAndUser,
- update: adminsAndUser,
+ admin: authenticated,
+ create: authenticated,
+ delete: authenticated,
+ read: authenticated,
+ update: authenticated,
},
admin: {
defaultColumns: ['name', 'email'],
@@ -26,34 +21,7 @@ const Users: CollectionConfig = {
name: 'name',
type: 'text',
},
- {
- name: 'roles',
- type: 'select',
- access: {
- create: admins,
- read: admins,
- update: admins,
- },
- defaultValue: ['user'],
- hasMany: true,
- hooks: {
- beforeChange: [ensureFirstUserIsAdmin],
- },
- options: [
- {
- label: 'admin',
- value: 'admin',
- },
- {
- label: 'user',
- value: 'user',
- },
- ],
- },
],
- hooks: {
- afterChange: [loginAfterCreate],
- },
timestamps: true,
}
diff --git a/templates/website/src/payload/endpoints/seed.ts b/templates/website/src/payload/endpoints/seed.ts
index 945b78ca9..506639bf8 100644
--- a/templates/website/src/payload/endpoints/seed.ts
+++ b/templates/website/src/payload/endpoints/seed.ts
@@ -1,4 +1,4 @@
-import type { PayloadHandler } from 'payload/config'
+import type { PayloadHandler } from 'payload'
import { seed as seedScript } from '../seed'
diff --git a/templates/website/src/payload/fields/hero.ts b/templates/website/src/payload/fields/hero.ts
index 9b171e859..0e0050793 100644
--- a/templates/website/src/payload/fields/hero.ts
+++ b/templates/website/src/payload/fields/hero.ts
@@ -1,4 +1,4 @@
-import type { Field } from 'payload/types'
+import type { Field } from 'payload'
import {
FixedToolbarFeature,
diff --git a/templates/website/src/payload/fields/link.ts b/templates/website/src/payload/fields/link.ts
index 54c622d09..e08de5e27 100644
--- a/templates/website/src/payload/fields/link.ts
+++ b/templates/website/src/payload/fields/link.ts
@@ -1,4 +1,4 @@
-import type { Field } from 'payload/types'
+import type { Field } from 'payload'
import deepMerge from '../utilities/deepMerge'
diff --git a/templates/website/src/payload/fields/linkGroup.ts b/templates/website/src/payload/fields/linkGroup.ts
index 7fd53ce67..a4134bd34 100644
--- a/templates/website/src/payload/fields/linkGroup.ts
+++ b/templates/website/src/payload/fields/linkGroup.ts
@@ -1,4 +1,4 @@
-import type { ArrayField, Field } from 'payload/types'
+import type { ArrayField, Field } from 'payload'
import type { LinkAppearances } from './link'
diff --git a/templates/website/src/payload/fields/slug.ts b/templates/website/src/payload/fields/slug.ts
index 696f00131..b73ecba4f 100644
--- a/templates/website/src/payload/fields/slug.ts
+++ b/templates/website/src/payload/fields/slug.ts
@@ -1,4 +1,4 @@
-import type { Field } from 'payload/types'
+import type { Field } from 'payload'
import deepMerge from '../utilities/deepMerge'
import formatSlug from '../utilities/formatSlug'
diff --git a/templates/website/src/payload/globals/Footer/Footer.ts b/templates/website/src/payload/globals/Footer/Footer.ts
index 251aac509..b7f7e2408 100644
--- a/templates/website/src/payload/globals/Footer/Footer.ts
+++ b/templates/website/src/payload/globals/Footer/Footer.ts
@@ -1,4 +1,4 @@
-import type { GlobalConfig } from 'payload/types'
+import type { GlobalConfig } from 'payload'
import { link } from '../../fields/link'
import { revalidateFooter } from './hooks/revalidateFooter'
diff --git a/templates/website/src/payload/globals/Footer/hooks/revalidateFooter.ts b/templates/website/src/payload/globals/Footer/hooks/revalidateFooter.ts
index bb2f9e647..f6267c0fd 100644
--- a/templates/website/src/payload/globals/Footer/hooks/revalidateFooter.ts
+++ b/templates/website/src/payload/globals/Footer/hooks/revalidateFooter.ts
@@ -1,9 +1,11 @@
-import type { GlobalAfterChangeHook } from 'payload/types'
+import type { GlobalAfterChangeHook } from 'payload'
-import { revalidate } from '../../../utilities/revalidate'
+import { revalidateTag } from 'next/cache'
export const revalidateFooter: GlobalAfterChangeHook = ({ doc, req: { payload } }) => {
- void revalidate({ type: 'tag', collection: 'footer', payload, tag: 'global_footer' })
+ payload.logger.info(`Revalidating footer`)
+
+ revalidateTag('global_footer')
return doc
}
diff --git a/templates/website/src/payload/globals/Header/Header.ts b/templates/website/src/payload/globals/Header/Header.ts
index 2856f091a..0da762346 100644
--- a/templates/website/src/payload/globals/Header/Header.ts
+++ b/templates/website/src/payload/globals/Header/Header.ts
@@ -1,4 +1,4 @@
-import type { GlobalConfig } from 'payload/types'
+import type { GlobalConfig } from 'payload'
import { link } from '../../fields/link'
import { revalidateHeader } from './hooks/revalidateHeader'
diff --git a/templates/website/src/payload/globals/Header/hooks/revalidateHeader.ts b/templates/website/src/payload/globals/Header/hooks/revalidateHeader.ts
index e8682a557..7315cc260 100644
--- a/templates/website/src/payload/globals/Header/hooks/revalidateHeader.ts
+++ b/templates/website/src/payload/globals/Header/hooks/revalidateHeader.ts
@@ -1,9 +1,11 @@
-import type { GlobalAfterChangeHook } from 'payload/types'
+import type { GlobalAfterChangeHook } from 'payload'
-import { revalidate } from '../../../utilities/revalidate'
+import { revalidateTag } from 'next/cache'
export const revalidateHeader: GlobalAfterChangeHook = ({ doc, req: { payload } }) => {
- void revalidate({ type: 'tag', collection: 'header', payload, tag: 'global_header' })
+ payload.logger.info(`Revalidating header`)
+
+ revalidateTag('global_header')
return doc
}
diff --git a/templates/website/src/payload/hooks/formatSlug.ts b/templates/website/src/payload/hooks/formatSlug.ts
index b5c787201..43190f88c 100644
--- a/templates/website/src/payload/hooks/formatSlug.ts
+++ b/templates/website/src/payload/hooks/formatSlug.ts
@@ -1,4 +1,4 @@
-import type { FieldHook } from 'payload/types'
+import type { FieldHook } from 'payload'
const format = (val: string): string =>
val
diff --git a/templates/website/src/payload/hooks/populatePublishedAt.ts b/templates/website/src/payload/hooks/populatePublishedAt.ts
index 09567e924..de974f7b6 100644
--- a/templates/website/src/payload/hooks/populatePublishedAt.ts
+++ b/templates/website/src/payload/hooks/populatePublishedAt.ts
@@ -1,4 +1,4 @@
-import type { CollectionBeforeChangeHook } from 'payload/types'
+import type { CollectionBeforeChangeHook } from 'payload'
export const populatePublishedAt: CollectionBeforeChangeHook = ({ data, operation, req }) => {
if (operation === 'create' || operation === 'update') {
diff --git a/templates/website/src/payload/hooks/revalidatePage.ts b/templates/website/src/payload/hooks/revalidatePage.ts
deleted file mode 100644
index 4377b96d4..000000000
--- a/templates/website/src/payload/hooks/revalidatePage.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import type { CollectionAfterChangeHook } from 'payload/types'
-
-// ensure that the home page is revalidated at '/' instead of '/home'
-export const formatAppURL = ({ doc }): string => {
- const pathToUse = doc.slug === 'home' ? '' : doc.slug
- const { pathname } = new URL(`${process.env.PAYLOAD_PUBLIC_SERVER_URL}/${pathToUse}`)
- return pathname
-}
-
-// Revalidate the page in the background, so the user doesn't have to wait
-// Notice that the hook itself is not async and we are not awaiting `revalidate`
-export const revalidatePage: CollectionAfterChangeHook = ({ doc, req }) => {
- const revalidate = async (): Promise => {
- let url
-
- try {
- url = formatAppURL({ doc })
- const res = await fetch(
- `${process.env.PAYLOAD_PUBLIC_SERVER_URL}/next/revalidate?secret=${process.env.REVALIDATION_KEY}&revalidatePath=${url}`,
- )
-
- if (res.ok) {
- req.payload.logger.info(`Revalidated path ${url}`)
- } else {
- req.payload.logger.error(`Error revalidating path ${url}`)
- }
- } catch (err: unknown) {
- req.payload.logger.error(`Error hitting revalidate route for ${url}`)
- }
- }
-
- void revalidate()
-
- return doc
-}
diff --git a/templates/website/src/payload/hooks/revalidateRedirect.ts b/templates/website/src/payload/hooks/revalidateRedirect.ts
deleted file mode 100644
index cda243e2b..000000000
--- a/templates/website/src/payload/hooks/revalidateRedirect.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import type { CollectionAfterChangeHook } from 'payload/types'
-
-import { revalidate } from '../utilities/revalidate'
-
-export const revalidateRedirect: CollectionAfterChangeHook = ({ doc, req: { payload } }) => {
- void revalidate({ type: 'tag', collection: 'redirects', payload, tag: `redirects_${doc.from}` })
-
- return doc
-}
diff --git a/templates/website/src/payload/hooks/revalidateRedirects.ts b/templates/website/src/payload/hooks/revalidateRedirects.ts
new file mode 100644
index 000000000..b5cc3ae4c
--- /dev/null
+++ b/templates/website/src/payload/hooks/revalidateRedirects.ts
@@ -0,0 +1,11 @@
+import type { CollectionAfterChangeHook } from 'payload'
+
+import { revalidateTag } from 'next/cache'
+
+export const revalidateRedirects: CollectionAfterChangeHook = ({ doc, req: { payload } }) => {
+ payload.logger.info(`Revalidating redirects`)
+
+ revalidateTag('redirects')
+
+ return doc
+}
diff --git a/templates/website/src/payload/seed/home-static.ts b/templates/website/src/payload/seed/home-static.ts
new file mode 100644
index 000000000..7de9ecfaa
--- /dev/null
+++ b/templates/website/src/payload/seed/home-static.ts
@@ -0,0 +1,634 @@
+import type { Page } from '../../payload-types'
+
+// Used for pre-seeded content so that the homepage is not empty
+// @ts-expect-error
+export const homeStatic: Page = {
+ slug: 'home',
+ _status: 'published',
+ hero: {
+ type: 'lowImpact',
+ richText: {
+ root: {
+ type: 'root',
+ children: [
+ {
+ type: 'heading',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Payload Website Template',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ tag: 'h1',
+ version: 1,
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ type: 'link',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Visit the admin dashboard',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ fields: {
+ linkType: 'custom',
+ newTab: false,
+ url: '/admin',
+ },
+ format: '',
+ indent: 0,
+ version: 2,
+ },
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: ' to make your account and seed content for your website.',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ textFormat: 0,
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ version: 1,
+ },
+ },
+ },
+ /* layout: [
+ {
+ blockName: 'Content Block',
+ blockType: 'content',
+ columns: [
+ {
+ richText: {
+ root: {
+ type: 'root',
+ children: [
+ {
+ type: 'heading',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Core features',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ tag: 'h2',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ version: 1,
+ },
+ },
+ size: 'full',
+ },
+ {
+ enableLink: false,
+ link: {
+ label: '',
+ reference: null,
+ url: '',
+ },
+ richText: {
+ root: {
+ type: 'root',
+ children: [
+ {
+ type: 'heading',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Admin Dashboard',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ tag: 'h3',
+ version: 1,
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: "Manage this site's pages and posts from the ",
+ version: 1,
+ },
+ {
+ type: 'link',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'admin dashboard',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ fields: {
+ linkType: 'custom',
+ newTab: false,
+ url: '/admin',
+ },
+ format: '',
+ indent: 0,
+ version: 2,
+ },
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: '.',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ textFormat: 0,
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ version: 1,
+ },
+ },
+ size: 'oneThird',
+ },
+ {
+ enableLink: false,
+ link: {
+ label: '',
+ reference: null,
+ url: '',
+ },
+ richText: {
+ root: {
+ type: 'root',
+ children: [
+ {
+ type: 'heading',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Preview',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ tag: 'h3',
+ version: 1,
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Using versions, drafts, and preview, editors can review and share their changes before publishing them.',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ textFormat: 0,
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ version: 1,
+ },
+ },
+ size: 'oneThird',
+ },
+ {
+ enableLink: false,
+ link: {
+ label: '',
+ reference: null,
+ url: '',
+ },
+ richText: {
+ root: {
+ type: 'root',
+ children: [
+ {
+ type: 'heading',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Page Builder',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ tag: 'h3',
+ version: 1,
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Custom page builder allows you to create unique page, post, and project layouts for any type of content.',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ textFormat: 0,
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ version: 1,
+ },
+ },
+ size: 'oneThird',
+ },
+ {
+ enableLink: false,
+ link: {
+ label: '',
+ reference: null,
+ url: '',
+ },
+ richText: {
+ root: {
+ type: 'root',
+ children: [
+ {
+ type: 'heading',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'SEO',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ tag: 'h3',
+ version: 1,
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Editors have complete control over SEO data and site content directly from the ',
+ version: 1,
+ },
+ {
+ type: 'link',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'admin dashboard',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ fields: {
+ linkType: 'custom',
+ newTab: false,
+ url: '/admin',
+ },
+ format: '',
+ indent: 0,
+ version: 2,
+ },
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: '.',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ textFormat: 0,
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ version: 1,
+ },
+ },
+ size: 'oneThird',
+ },
+ {
+ enableLink: false,
+ link: {
+ label: '',
+ reference: null,
+ url: '',
+ },
+ richText: {
+ root: {
+ type: 'root',
+ children: [
+ {
+ type: 'heading',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Dark Mode',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ tag: 'h3',
+ version: 1,
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Users will experience this site in their preferred color scheme and each block can be inverted.',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ textFormat: 0,
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ version: 1,
+ },
+ },
+ size: 'oneThird',
+ },
+ ],
+ },
+ {
+ blockName: 'Archive Block',
+ blockType: 'archive',
+ categories: [],
+ introContent: {
+ root: {
+ type: 'root',
+ children: [
+ {
+ type: 'heading',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'Recent posts',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ tag: 'h3',
+ version: 1,
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'The posts below are displayed in an "Archive" layout building block which is an extremely powerful way to display documents on a page. It can be auto-populated by collection or by category, or posts can be individually selected. Pagination controls will automatically appear if the number of results exceeds the number of items per page.',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ textFormat: 0,
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ version: 1,
+ },
+ },
+ populateBy: 'collection',
+ relationTo: 'posts',
+ },
+ {
+ blockName: 'CTA',
+ blockType: 'cta',
+ links: [
+ {
+ link: {
+ type: 'custom',
+ appearance: 'default',
+ label: 'All posts',
+ url: '/posts',
+ },
+ },
+ ],
+ richText: {
+ root: {
+ type: 'root',
+ children: [
+ {
+ type: 'heading',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'This is a call to action',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ tag: 'h3',
+ version: 1,
+ },
+ {
+ type: 'paragraph',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'This is a custom layout building block ',
+ version: 1,
+ },
+ {
+ type: 'link',
+ children: [
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: 'configured in the admin dashboard',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ fields: {
+ linkType: 'custom',
+ newTab: false,
+ url: '/admin',
+ },
+ format: '',
+ indent: 0,
+ version: 2,
+ },
+ {
+ type: 'text',
+ detail: 0,
+ format: 0,
+ mode: 'normal',
+ style: '',
+ text: '.',
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ textFormat: 0,
+ version: 1,
+ },
+ ],
+ direction: 'ltr',
+ format: '',
+ indent: 0,
+ version: 1,
+ },
+ },
+ },
+ ], */
+ meta: {
+ description: 'An open-source website built with Payload and Next.js.',
+ title: 'Payload Website Template',
+ },
+ title: 'Home',
+}
diff --git a/templates/website/src/payload/seed/index.ts b/templates/website/src/payload/seed/index.ts
index 537af97b9..826547085 100644
--- a/templates/website/src/payload/seed/index.ts
+++ b/templates/website/src/payload/seed/index.ts
@@ -59,7 +59,7 @@ export const seed = async (payload: Payload): Promise => {
payload.logger.info(`— Seeding demo author and user...`)
await Promise.all(
- ['demo-author@payloadcms.com', 'demo-user@payloadcms.com'].map(async (email) => {
+ ['demo-author@payloadcms.com'].map(async (email) => {
await payload.delete({
collection: 'users',
where: {
@@ -78,16 +78,6 @@ export const seed = async (payload: Payload): Promise => {
name: 'Demo Author',
email: 'demo-author@payloadcms.com',
password: 'password',
- roles: ['admin'],
- },
- }),
- await payload.create({
- collection: 'users',
- data: {
- name: 'Demo User',
- email: 'demo-user@payloadcms.com',
- password: 'password',
- roles: ['user'],
},
}),
])
@@ -311,7 +301,7 @@ export const seed = async (payload: Payload): Promise => {
type: 'custom',
label: 'Source Code',
newTab: true,
- url: 'https://github.com/payloadcms/payload/tree/main/templates/website',
+ url: 'https://github.com/payloadcms/payload/tree/beta/templates/website',
},
},
{
diff --git a/templates/website/src/payload/seed/post-1.ts b/templates/website/src/payload/seed/post-1.ts
index 33be80944..404e5abcf 100644
--- a/templates/website/src/payload/seed/post-1.ts
+++ b/templates/website/src/payload/seed/post-1.ts
@@ -181,7 +181,7 @@ export const post1: Partial = {
id: '664397d9e0ef87fa1fec2fc0',
blockName: '',
blockType: 'code',
- code: "import { CollectionConfig } from 'payload/types'\n\nexport const Orders: CollectionConfig = {\n slug: 'orders',\n fields: [\n {\n name: 'total',\n type: 'number',\n required: true,\n },\n {\n name: 'placedBy',\n type: 'relationship',\n relationTo: 'customers',\n required: true,\n },\n ],\n}",
+ code: "import { CollectionConfig } from 'payload'\n\nexport const Orders: CollectionConfig = {\n slug: 'orders',\n fields: [\n {\n name: 'total',\n type: 'number',\n required: true,\n },\n {\n name: 'placedBy',\n type: 'relationship',\n relationTo: 'customers',\n required: true,\n },\n ],\n}",
language: 'typescript',
},
format: '',
diff --git a/templates/website/src/payload/seed/post-2.ts b/templates/website/src/payload/seed/post-2.ts
index b989b5c12..ad57c687f 100644
--- a/templates/website/src/payload/seed/post-2.ts
+++ b/templates/website/src/payload/seed/post-2.ts
@@ -181,7 +181,7 @@ export const post2: Partial = {
id: '664397d9e0ef87fa1fec2fc0',
blockName: '',
blockType: 'code',
- code: "import { CollectionConfig } from 'payload/types'\n\nexport const Orders: CollectionConfig = {\n slug: 'orders',\n fields: [\n {\n name: 'total',\n type: 'number',\n required: true,\n },\n {\n name: 'placedBy',\n type: 'relationship',\n relationTo: 'customers',\n required: true,\n },\n ],\n}",
+ code: "import { CollectionConfig } from 'payload'\n\nexport const Orders: CollectionConfig = {\n slug: 'orders',\n fields: [\n {\n name: 'total',\n type: 'number',\n required: true,\n },\n {\n name: 'placedBy',\n type: 'relationship',\n relationTo: 'customers',\n required: true,\n },\n ],\n}",
language: 'typescript',
},
format: '',
diff --git a/templates/website/src/payload/seed/post-3.ts b/templates/website/src/payload/seed/post-3.ts
index 1ed35ab88..39f678e3b 100644
--- a/templates/website/src/payload/seed/post-3.ts
+++ b/templates/website/src/payload/seed/post-3.ts
@@ -181,7 +181,7 @@ export const post3: Partial = {
id: '664397d9e0ef87fa1fec2fc0',
blockName: '',
blockType: 'code',
- code: "import { CollectionConfig } from 'payload/types'\n\nexport const Orders: CollectionConfig = {\n slug: 'orders',\n fields: [\n {\n name: 'total',\n type: 'number',\n required: true,\n },\n {\n name: 'placedBy',\n type: 'relationship',\n relationTo: 'customers',\n required: true,\n },\n ],\n}",
+ code: "import { CollectionConfig } from 'payload'\n\nexport const Orders: CollectionConfig = {\n slug: 'orders',\n fields: [\n {\n name: 'total',\n type: 'number',\n required: true,\n },\n {\n name: 'placedBy',\n type: 'relationship',\n relationTo: 'customers',\n required: true,\n },\n ],\n}",
language: 'typescript',
},
format: '',
diff --git a/templates/website/src/payload/utilities/formatSlug.ts b/templates/website/src/payload/utilities/formatSlug.ts
index b5c787201..43190f88c 100644
--- a/templates/website/src/payload/utilities/formatSlug.ts
+++ b/templates/website/src/payload/utilities/formatSlug.ts
@@ -1,4 +1,4 @@
-import type { FieldHook } from 'payload/types'
+import type { FieldHook } from 'payload'
const format = (val: string): string =>
val
diff --git a/templates/website/src/payload/utilities/revalidate.ts b/templates/website/src/payload/utilities/revalidate.ts
deleted file mode 100644
index f6f18577a..000000000
--- a/templates/website/src/payload/utilities/revalidate.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import type { RevalidationType } from '@/next/revalidate/route'
-import type { Payload } from 'payload'
-
-export const revalidate = async (args: {
- collection: string
- path?: string
- payload: Payload
- tag?: string
- type?: RevalidationType
-}): Promise => {
- const { type = 'path', collection, path, payload, tag } = args
-
- try {
- const baseUrl = `${process.env.PAYLOAD_PUBLIC_SERVER_URL}/next/revalidate?secret=${process.env.REVALIDATION_KEY}`
- const url = baseUrl + (type === 'path' ? `&path=${path}` : `&tag=${tag}&type=tag`)
-
- const res = await fetch(url)
-
- if (res.ok) {
- switch (type) {
- case 'path':
- payload.logger.info(`Revalidated path '${path}' in collection '${collection}'`)
- break
- case 'tag':
- payload.logger.info(`Revalidated tag '${tag}'`)
- break
- }
- } else {
- switch (type) {
- case 'path':
- payload.logger.error(
- `Error revalidating path '${path}' in collection '${collection}`,
- res,
- )
- break
- case 'tag':
- payload.logger.error(`Error revalidating tag '${tag}' in '${collection}`, res)
- break
- }
- }
- } catch (err: unknown) {
- switch (type) {
- case 'path':
- payload.logger.error(`Error revalidating path '${path}' in collection '${collection}`, err)
- break
- case 'tag':
- payload.logger.error(`Error revalidating tag '${tag}' in '${collection}`, err)
- break
- }
- }
-}
diff --git a/templates/website/tsconfig.json b/templates/website/tsconfig.json
index 6f79514cb..6523fc3bb 100644
--- a/templates/website/tsconfig.json
+++ b/templates/website/tsconfig.json
@@ -27,7 +27,7 @@
"@/*": ["./src/app/*"]
}
},
- "include": ["**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "include": ["**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "redirects.js", "next.config.js"],
"exclude": ["node_modules"],
"ts-node": {
"transpileOnly": true,