# Payload Nested Pages Plugin [![NPM](https://img.shields.io/npm/v/payload-plugin-nested-pages)](https://www.npmjs.com/package/payload-plugin-nested-pages) A plugin for [Payload CMS](https://github.com/payloadcms/payload) to easily allow for documents to be nested inside one another. Core features: - Allows for [parent/child](#parent) relationships between documents - Automatically populates [breadcrumbs](#breadcrumbs) data ## Installation ```bash yarn add payload-plugin-nested-pages # OR npm i payload-plugin-nested-pages ``` ## Basic Usage In the `plugins` array of your [Payload config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options): ```js import { buildConfig } from 'payload/config'; import nestedPages from 'payload-plugin-nestedPages'; const config = buildConfig({ collections: [ { slug: 'pages', fields: [ { name: 'title', type: 'text' }, { name: 'slug', type: 'text' } ] } ], plugins: [ nestedPages({ collections: ['pages'], generateLabel: (_, doc) => doc.title, generateURL: (docs) => docs.reduce((url, doc) => `${url}/${doc.slug}`, ''), }) ] }); export default config; ``` ### Fields #### Parent The `parent` relationship field is automatically added to every document which allows editors to choose another document from the same collection to act as the direct parent. #### Breadcrumbs The `breadcrumbs` field is an array which dynamically populates all parent relationships of a document up to the top level. It does not store any data in the database, and instead, acts as a `virtual` field which is dynamically populated each time the document is loaded. The `breadcrumbs` array stores the following fields: - `label` The label of the breadcrumb. This field is automatically set to either the `collection.admin.useAsTitle` (if defined) or is set to the `ID` of the document. You can also dynamically define the `label` by passing a function to the options property of [`generateLabel`](#generateLabel). - `url` The URL of the breadcrumb. By default, this field is undefined. You can manually define this field by passing a property called function to the plugin options property of [`generateURL`](#generateURL). ### Options #### `collections` An array of collections slugs to enable nested pages. #### `generateLabel` Each `breadcrumb` has a required `label` field. By default, its value will be set to the collection's `admin.useAsTitle` or fallback the the `ID` of the document. You can also pass a function to dynamically set the `label` of your breadcrumb. ```js { plugins: [ ... nestedPages({ ... generateLabel: (_, doc) => doc.title // NOTE: 'title' is a hypothetical field }) ] ``` The function takes two arguments and returns a string: 1. `breadcrumbs` - an array of the breadcrumbs up to that point 2. `currentDoc` - the current document being edited #### `generateURL` A function that allows you to dynamically generate each breadcrumb `url`. Each `breadcrumb` has an optional `url` field which is undefined by default. For example, you might want to format a full URL to contain all of the breadcrumbs up to that point, like `/about-us/company/our-team`. ```js plugins: [ ... nestedPages({ ... generateURL: (docs) => docs.reduce((url, doc) => `${url}/${doc.slug}`, ''), // NOTE: 'slug' is a hypothetical field }) ] ``` This function takes two arguments and returns a string: 1. `breadcrumbs` - an array of the breadcrumbs up to that point 1. `currentDoc` - the current document being edited #### `parentFieldSlug` When defined, the `parent` field will not be provided for you automatically, and instead, expects you to add your own `parent` field to each collection manually. This gives you complete control over where you put the field in your admin dashboard, etc. Set this property to the `name` of your custom field. #### `breadcrumbsFieldSlug` When defined, the `breadcrumbs` field will not be provided for you, and instead, expects your to add your own `breadcrumbs` field to each collection manually. Set this property to the `name` of your custom field. > Note - if you opt out of automatically being provided a `parent` or `breadcrumbs` field, you need to make sure that both fields are placed at the top-level of your document. They cannot exist within any nested data structures like a `group`, `array`, or `blocks`. ## More You can also extend the built-in `parent` and `breadcrumbs` fields on a page-by-page basis by importing helper methods as follows: ```js import { CollectionConfig } from 'payload/types'; import createParentField from 'payload-plugin-nested-pages/fields/parent'; import createBreadcrumbsField from 'payload-plugin-nested-pages/fields/breadcrumbs'; const examplePageConfig: CollectionConfig = { slug: 'pages', fields: [ createParentField( // First argument is equal to the slug of the collection // that the field references 'pages', // Second argument is equal to field overrides that you specify, // which will be merged into the base parent field config { admin: { position: 'sidebar', }, }, ), createBreadcrumbsField( // First argument is equal to the slug of the collection // that the field references 'pages', // Argument equal to field overrides that you specify, // which will be merged into the base `breadcrumbs` field config { label: 'Page Breadcrumbs', } ) ] } ``` ## TypeScript All types can be directly imported: ```js import { NestedPagesConfig, GenerateURL, GenerateLabel } from 'payload-plugin-nested-pages/dist/types'; ``` ## Screenshots