diff --git a/docs/admin/components.mdx b/docs/admin/components.mdx index 07b2ccb00..2458ed48f 100644 --- a/docs/admin/components.mdx +++ b/docs/admin/components.mdx @@ -1,7 +1,7 @@ --- title: Swap in your own React components label: Custom Components -order: 40 +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, nextjs --- diff --git a/docs/admin/hooks.mdx b/docs/admin/hooks.mdx index dd83eaa48..4c2c151bc 100644 --- a/docs/admin/hooks.mdx +++ b/docs/admin/hooks.mdx @@ -1,7 +1,7 @@ --- title: React Hooks label: React Hooks -order: 70 +order: 40 desc: Make use of all of the powerful React hooks that Payload provides. keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs --- diff --git a/docs/admin/overview.mdx b/docs/admin/overview.mdx index e18c673f1..a02a7d94e 100644 --- a/docs/admin/overview.mdx +++ b/docs/admin/overview.mdx @@ -6,7 +6,7 @@ desc: Manage your data and customize the Payload Admin Panel by swapping in your keywords: admin, components, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, nextjs --- -Payload dynamically generates a beautiful, [fully type-safe](../typescript/overview) Admin Panel to manage your users and data. It is highly performant, even with 100+ fields, and is translated in over 30 languages. Within the Admin Panel you can manage content, [render your site](../live-preview/overview), preview drafts, [diff versions](../versions/overview), and so much more. +Payload dynamically generates a beautiful, [fully type-safe](../typescript/overview) Admin Panel to manage your users and data. It is highly performant, even with 100+ fields, and is translated in over 30 languages. Within the Admin Panel you can manage content, [render your site](../live-preview/overview), [preview drafts](./preview), [diff versions](../versions/overview), and so much more. The Admin Panel is designed to [white-label your brand](https://payloadcms.com/blog/white-label-admin-ui). You can endlessly customize and extend the Admin UI by swapping in your own [Custom Components](./components)—everything from simple field labels to entire views can be modified or replaced to perfectly tailor the interface for your editors. diff --git a/docs/admin/preview.mdx b/docs/admin/preview.mdx new file mode 100644 index 000000000..f55ab698e --- /dev/null +++ b/docs/admin/preview.mdx @@ -0,0 +1,219 @@ +--- +title: Preview +label: Preview +order: 50 +desc: Enable links to your front-end to preview published or draft content. +keywords: admin, components, preview, documentation, Content Management System, cms, headless, javascript, node, react, nextjs +--- + +Preview is a feature that allows you to generate a direct link to your front-end application. When enabled, a "preview" button will appear on the Edit View within the [Admin Panel](./overview) with an href pointing to the URL you provide. This will provide your editors with a quick way of navigating to the front-end application where that Document's data is represented. Otherwise, they'd have to determine that URL themselves which is not always straightforward especially in complex apps. + +The Preview feature can also be used to achieve something known as "Draft Preview". With Draft Preview, you can navigate to your front-end application and enter "draft mode", where your queries are modified to fetch draft content instead of published content. This is useful for seeing how your content will look before being published. [More details](#draft-preview). + + + **Note:** + Preview is different than [Live Preview](../live-preview/overview). Live Preview loads your app within an iframe and renders it in the Admin Panel allowing you to see changes in real-time. Preview, on the other hand, allows you to generate a direct link to your front-end application. + + +To add Preview, pass a function to the `admin.preview` property in any [Collection Config](../configuration/collections#admin-options) or [Global Config](../configuration/globals#admin-options): + +```ts +import type { CollectionConfig } from 'payload' + +export const Pages: CollectionConfig = { + slug: 'pages', + admin: { + preview: ({ slug }) => `http://localhost:3000/${slug}`, + }, + fields: [ + { + name: 'slug', + type: 'text', + } + ], +} +``` + +## Options + +The `preview` function resolves to a string that points to your front-end application with additional URL parameters. This can be an absolute URL or a relative path, and can run async if needed. + +The following arguments are provided to the `preview` function: + +| Path | Description | +| ------------------ | ----------------------------------------------------------------------------------------------------------------- | +| **`doc`** | The data of the Document being edited. This includes changes that have not yet been saved. | +| **`options`** | An object with additional properties. | + +The `options` object contains the following properties: + +| Path | Description | +| ------------------ | ----------------------------------------------------------------------------------------------------------------- | +| **`locale`** | The current locale of the Document being edited. | +| **`req`** | The Payload Request object. | +| **`token`** | The JWT token of the currently authenticated in user. | + +If your application requires a fully qualified URL, such as within deploying to Vercel Preview Deployments, you can use the `req` property to build this URL: + +```ts +preview: (doc, { req }) => `${req.protocol}//${req.host}/${doc.slug}` // highlight-line +``` + +## Draft Preview + +The Preview feature can be used to achieve "Draft Preview", where you enter into a "draft mode" after clicking the preview button. While in "draft mode", you can adjust your page's query to include the `draft: true` in its params. Payload will read this param on the request, and when present, send back a draft document as opposed to a published one based on the document's `_status` field. + +To enter draft mode, the URL provided to the `preview` function can point to a custom endpoint in your front-end application that sets a cookie or session variable to indicate that you are in "draft mode". This is framework specific, so the mechanisms here very from framework to framework although the underlying concept is the same. + +### Next.js + +If you're using Next.js, you can do the following code to enter draft mode. + +#### Step 1: Create an API Route + +First, format your `preview` function to point to a custom endpoint that you'll open on your front-end. This URL will include a few key query search params: + +```ts +import type { CollectionConfig } from 'payload' + +export const Pages: CollectionConfig = { + slug: 'pages', + admin: { + preview: ({ slug }, { req }) => { + const path = `/${slug}` + + const encodedParams = new URLSearchParams({ + slug, + collection, + path, + previewSecret: process.env.PREVIEW_SECRET + }) + + return `/next/preview?${encodedParams.toString()}` // highlight-line + } + }, + fields: [ + { + name: 'slug', + type: 'text', + } + ], +} +``` + +#### Step 2: Create the Preview Route + +Then, create an API route that verifies the preview secret, authenticates the user, and enters draft mode: + +`/preview/route.ts` + +```ts +import type { CollectionSlug, PayloadRequest, getPayload } from 'payload' + +import { draftMode } from 'next/headers' +import { redirect } from 'next/navigation' + +import configPromise from '@payload-config' + +const payloadToken = 'payload-token' + +export async function GET( + req: { + cookies: { + get: (name: string) => { + value: string + } + } + } & Request, +): Promise { + const payload = await getPayload({ config: configPromise }) + + const { searchParams } = new URL(req.url) + + const path = searchParams.get('path') + const collection = searchParams.get('collection') as CollectionSlug + const slug = searchParams.get('slug') + const previewSecret = searchParams.get('previewSecret') + + if (previewSecret !== process.env.PREVIEW_SECRET) { + return new Response('You are not allowed to preview this page', { status: 403 }) + } + + if (!path || !collection || !slug) { + return new Response('Insufficient search params', { status: 404 }) + } + + if (!path.startsWith('/')) { + return new Response('This endpoint can only be used for relative previews', { status: 500 }) + } + + let user + + try { + user = await payload.auth({ + req: req as unknown as PayloadRequest, + headers: req.headers, + }) + } catch (error) { + payload.logger.error({ err: error }, 'Error verifying token for live preview') + return new Response('You are not allowed to preview this page', { status: 403 }) + } + + const draft = await draftMode() + + // You can add additional checks here to see if the user is allowed to preview this page + if (!user) { + draft.disable() + return new Response('You are not allowed to preview this page', { status: 403 }) + } + + draft.enable() + + redirect(path) +} +``` + +#### Step 3: Query Draft Content + +Finally, in your front-end application, you can detect draft mode and adjust your queries to include drafts: + +`/pages/[slug].tsx` + +```ts +export default async function Page({ params: paramsPromise }) { + const { slug = 'home' } = await paramsPromise + + const { isEnabled: isDraftMode } = await draftMode() + + const payload = await getPayload({ config }) + + const page = await payload.find({ + collection: 'pages', + depth: 0, + draft: isDraftMode, // highlight-line + limit: 1, + overrideAccess: isDraftMode, + where: { + slug: { + equals: slug, + }, + }, + })?.then(({ docs }) => docs?.[0]) + + if (page === null) { + return notFound() + } + + return ( +
+

{page?.title}

+
+ ) +} +``` + + + **Note:** + For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples). + + diff --git a/docs/admin/views.mdx b/docs/admin/views.mdx index 25d3bfdec..e7eb88a8d 100644 --- a/docs/admin/views.mdx +++ b/docs/admin/views.mdx @@ -1,7 +1,7 @@ --- title: Customizing Views label: Customizing Views -order: 50 +order: 30 desc: keywords: --- @@ -289,7 +289,7 @@ The following options are available: ### Document Tabs -Each Document View can be given a new tab in the Edit View, if desired. Tabs are highly configurable, from as simple as changing the label to swapping out the entire component, they can be modified in any way. To add or customize tabs in the Edit View, use the `tab` key: +Each Custom View can be given a new tab in the Edit View, if desired. Tabs are highly configurable, from as simple as changing the label to swapping out the entire component, they can be modified in any way. To add or customize tabs in the Edit View, use the `tab` key: ```ts import type { SanitizedCollectionConfig } from 'payload' diff --git a/docs/configuration/collections.mdx b/docs/configuration/collections.mdx index e484626d5..8416e7729 100644 --- a/docs/configuration/collections.mdx +++ b/docs/configuration/collections.mdx @@ -124,7 +124,7 @@ The following options are available: | **`enableRichTextLink`** | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. | | **`enableRichTextRelationship`** | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. | | **`meta`** | Page metadata overrides to apply to this Collection within the Admin Panel. [More details](../admin/metadata). | -| **`preview`** | Function to generate preview URLs within the Admin Panel that can point to your app. [More details](#preview). | +| **`preview`** | Function to generate preview URLs within the Admin Panel that can point to your app. [More details](../admin/preview). | | **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). | | **`components`** | Swap in your own React components to be used within this Collection. [More details](#custom-components). | | **`listSearchableFields`** | Specify which fields should be searched in the List search view. [More details](#list-searchable-fields). | @@ -162,7 +162,7 @@ The following options are available: | **`edit.SaveButton`** | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. | | **`edit.SaveDraftButton`** | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. | | **`edit.PublishButton`** | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. | -| **`edit.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](#preview) must be enabled. | +| **`edit.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](../admin/preview) must be enabled. | | **`edit.Upload`** | Replace the default Upload component with a Custom Component. [Upload](../upload/overview) must be enabled. | | **`views`** | Override or create new views within the Admin Panel. [More details](../admin/views). | @@ -171,51 +171,6 @@ The following options are available: For details on how to build Custom Components, see [Building Custom Components](../admin/components#building-custom-components). -### Preview - -It is possible to display a Preview Button within the Edit View of the Admin Panel. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes. - -To configure the Preview Button, set the `admin.preview` property to a function in your Collection Config: - -```ts -import type { CollectionConfig } from 'payload' - -export const Posts: CollectionConfig = { - // ... - admin: { - // highlight-start - preview: (doc, { locale }) => { - if (doc?.slug) { - return `/${doc.slug}?locale=${locale}` - } - - return null - }, - // highlight-end - }, -} -``` - -The `preview` property resolves to a string that points to your front-end application with additional URL parameters. This can be an absolute URL or a relative path. - -The preview function receives two arguments: - -| Argument | Description | -| --- | --- | -| **`doc`** | The Document being edited. | -| **`ctx`** | An object containing `locale`, `token`, and `req` properties. The `token` is the currently logged-in user's JWT. | - -If your application requires a fully qualified URL, such as within deploying to Vercel Preview Deployments, you can use the `req` property to build this URL: - -```ts -preview: (doc, { req }) => `${req.protocol}//${req.host}/${doc.slug}` // highlight-line -``` - - - **Note:** - For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples). - - ### Pagination All Collections receive their own List View which displays a paginated list of documents that can be sorted and filtered. The pagination behavior of the List View can be customized on a per-Collection basis, and uses the same [Pagination](../queries/pagination) API that Payload provides. diff --git a/docs/configuration/globals.mdx b/docs/configuration/globals.mdx index 7f3db0792..2ae7cc28b 100644 --- a/docs/configuration/globals.mdx +++ b/docs/configuration/globals.mdx @@ -120,7 +120,7 @@ The following options are available: | **`group`** | Text or localization object used to group Collection and Global links in the admin navigation. Set to `false` to hide the link from the navigation while keeping its routes accessible. | | **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Global from navigation and admin routing. | | **`components`** | Swap in your own React components to be used within this Global. [More details](#custom-components). | -| **`preview`** | Function to generate a preview URL within the Admin Panel for this Global that can point to your app. [More details](#preview). | +| **`preview`** | Function to generate a preview URL within the Admin Panel for this Global that can point to your app. [More details](../admin/preview). | | **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). | | **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this collection. | | **`meta`** | Page metadata overrides to apply to this Global within the Admin Panel. [More details](../admin/metadata). | @@ -151,7 +151,7 @@ The following options are available: | **`elements.SaveButton`** | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. | | **`elements.SaveDraftButton`** | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. | | **`elements.PublishButton`** | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. | -| **`elements.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](#preview) must be enabled. | +| **`elements.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](../admin/preview) must be enabled. | | **`views`** | Override or create new views within the Admin Panel. [More details](../admin/views). | @@ -159,43 +159,6 @@ The following options are available: For details on how to build Custom Components, see [Building Custom Components](../admin/components#building-custom-components). -### Preview - -It is possible to display a Preview Button within the Edit View of the Admin Panel. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes. - -To configure the Preview Button, set the `admin.preview` property to a function in your Global Config: - -```ts -import { GlobalConfig } from 'payload' - -export const MainMenu: GlobalConfig = { - // ... - admin: { - // highlight-start - preview: (doc, { locale }) => { - if (doc?.slug) { - return `/${doc.slug}?locale=${locale}` - } - - return null - }, - // highlight-end - }, -} -``` - -The preview function receives two arguments: - -| Argument | Description | -| --- | --- | -| **`doc`** | The Document being edited. | -| **`ctx`** | An object containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT. | - - - **Note:** - For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples). - - ## GraphQL You can completely disable GraphQL for this global by passing `graphQL: false` to your global config. This will completely disable all queries, mutations, and types from appearing in your GraphQL schema. diff --git a/docs/live-preview/overview.mdx b/docs/live-preview/overview.mdx index 761c55036..1efde35bc 100644 --- a/docs/live-preview/overview.mdx +++ b/docs/live-preview/overview.mdx @@ -28,6 +28,7 @@ const config = buildConfig({ } }) ``` + **Reminder:** Alternatively, you can define the `admin.livePreview` property on individual [Collection Admin Configs](../configuration/collections#admin-options) and [Global Admin Configs](../configuration/globals#admin-options). Settings defined here will be merged into the top-level as overrides.