templates: fix nested docs url generation for categories (#10403)

Fixes https://github.com/payloadcms/payload/issues/10374
This commit is contained in:
Paul
2025-01-06 14:18:54 -06:00
committed by GitHub
parent eadce5ea57
commit 398b6096f2
8 changed files with 233 additions and 74 deletions

View File

@@ -2,6 +2,7 @@ import type { CollectionConfig } from 'payload'
import { anyone } from '../access/anyone'
import { authenticated } from '../access/authenticated'
import { slugField } from '@/fields/slug'
export const Categories: CollectionConfig = {
slug: 'categories',
@@ -20,5 +21,6 @@ export const Categories: CollectionConfig = {
type: 'text',
required: true,
},
...slugField(),
],
}

View File

@@ -141,6 +141,12 @@ export const seed = async ({
collection: 'categories',
data: {
title: 'Technology',
breadcrumbs: [
{
label: 'Technology',
url: '/technology',
},
],
},
}),
@@ -148,6 +154,12 @@ export const seed = async ({
collection: 'categories',
data: {
title: 'News',
breadcrumbs: [
{
label: 'News',
url: '/news',
},
],
},
}),
@@ -155,12 +167,24 @@ export const seed = async ({
collection: 'categories',
data: {
title: 'Finance',
breadcrumbs: [
{
label: 'Finance',
url: '/finance',
},
],
},
}),
payload.create({
collection: 'categories',
data: {
title: 'Design',
breadcrumbs: [
{
label: 'Design',
url: '/design',
},
],
},
}),
@@ -168,6 +192,12 @@ export const seed = async ({
collection: 'categories',
data: {
title: 'Software',
breadcrumbs: [
{
label: 'Software',
url: '/software',
},
],
},
}),
@@ -175,6 +205,12 @@ export const seed = async ({
collection: 'categories',
data: {
title: 'Engineering',
breadcrumbs: [
{
label: 'Engineering',
url: '/engineering',
},
],
},
}),
])

View File

@@ -117,6 +117,9 @@ export interface Page {
} | null);
url?: string | null;
label: string;
/**
* Choose how the link should be rendered.
*/
appearance?: ('default' | 'outline') | null;
};
id?: string | null;
@@ -127,6 +130,9 @@ export interface Page {
layout: (CallToActionBlock | ContentBlock | MediaBlock | ArchiveBlock | FormBlock)[];
meta?: {
title?: string | null;
/**
* Maximum upload file size: 12MB. Recommended file size for images is <500KB.
*/
image?: (string | null) | Media;
description?: string | null;
};
@@ -164,6 +170,9 @@ export interface Post {
categories?: (string | Category)[] | null;
meta?: {
title?: string | null;
/**
* Maximum upload file size: 12MB. Recommended file size for images is <500KB.
*/
image?: (string | null) | Media;
description?: string | null;
};
@@ -280,6 +289,8 @@ export interface Media {
export interface Category {
id: string;
title: string;
slug?: string | null;
slugLock?: boolean | null;
parent?: (string | null) | Category;
breadcrumbs?:
| {
@@ -346,6 +357,9 @@ export interface CallToActionBlock {
} | null);
url?: string | null;
label: string;
/**
* Choose how the link should be rendered.
*/
appearance?: ('default' | 'outline') | null;
};
id?: string | null;
@@ -393,6 +407,9 @@ export interface ContentBlock {
} | null);
url?: string | null;
label: string;
/**
* Choose how the link should be rendered.
*/
appearance?: ('default' | 'outline') | null;
};
id?: string | null;
@@ -588,6 +605,9 @@ export interface Form {
)[]
| null;
submitButtonLabel?: string | null;
/**
* Choose whether to display an on-page message or redirect to a different page after they submit the form.
*/
confirmationType?: ('message' | 'redirect') | null;
confirmationMessage?: {
root: {
@@ -607,6 +627,9 @@ export interface Form {
redirect?: {
url: string;
};
/**
* Send custom emails when the form submits. Use comma separated lists to send the same email to multiple recipients. To reference a value from this form, wrap that field's name with double curly brackets, i.e. {{firstName}}. You can use a wildcard {{*}} to output all data and {{*:table}} to format it as an HTML table in the email.
*/
emails?:
| {
emailTo?: string | null;
@@ -615,6 +638,9 @@ export interface Form {
replyTo?: string | null;
emailFrom?: string | null;
subject: string;
/**
* Enter the message that should be sent in this email.
*/
message?: {
root: {
type: string;
@@ -642,6 +668,9 @@ export interface Form {
*/
export interface Redirect {
id: string;
/**
* You will need to rebuild the website when changing this field.
*/
from: string;
to?: {
type?: ('reference' | 'custom') | null;
@@ -677,6 +706,8 @@ export interface FormSubmission {
createdAt: string;
}
/**
* This is a collection of automatically created search results. These results are used by the global site search and will be updated automatically as documents in the CMS are created or updated.
*
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "search".
*/
@@ -1054,6 +1085,8 @@ export interface MediaSelect<T extends boolean = true> {
*/
export interface CategoriesSelect<T extends boolean = true> {
title?: T;
slug?: T;
slugLock?: T;
parent?: T;
breadcrumbs?:
| T

View File

@@ -49,6 +49,7 @@ export const plugins: Plugin[] = [
}),
nestedDocsPlugin({
collections: ['categories'],
generateURL: (docs) => docs.reduce((url, doc) => `${url}/${doc.slug}`, ''),
}),
seoPlugin({
generateTitle,

View File

@@ -2,6 +2,7 @@ import type { CollectionConfig } from 'payload'
import { anyone } from '../access/anyone'
import { authenticated } from '../access/authenticated'
import { slugField } from '@/fields/slug'
export const Categories: CollectionConfig = {
slug: 'categories',
@@ -20,5 +21,6 @@ export const Categories: CollectionConfig = {
type: 'text',
required: true,
},
...slugField(),
],
}

View File

@@ -141,6 +141,12 @@ export const seed = async ({
collection: 'categories',
data: {
title: 'Technology',
breadcrumbs: [
{
label: 'Technology',
url: '/technology',
},
],
},
}),
@@ -148,6 +154,12 @@ export const seed = async ({
collection: 'categories',
data: {
title: 'News',
breadcrumbs: [
{
label: 'News',
url: '/news',
},
],
},
}),
@@ -155,12 +167,24 @@ export const seed = async ({
collection: 'categories',
data: {
title: 'Finance',
breadcrumbs: [
{
label: 'Finance',
url: '/finance',
},
],
},
}),
payload.create({
collection: 'categories',
data: {
title: 'Design',
breadcrumbs: [
{
label: 'Design',
url: '/design',
},
],
},
}),
@@ -168,6 +192,12 @@ export const seed = async ({
collection: 'categories',
data: {
title: 'Software',
breadcrumbs: [
{
label: 'Software',
url: '/software',
},
],
},
}),
@@ -175,6 +205,12 @@ export const seed = async ({
collection: 'categories',
data: {
title: 'Engineering',
breadcrumbs: [
{
label: 'Engineering',
url: '/engineering',
},
],
},
}),
])

View File

@@ -117,6 +117,9 @@ export interface Page {
} | null);
url?: string | null;
label: string;
/**
* Choose how the link should be rendered.
*/
appearance?: ('default' | 'outline') | null;
};
id?: string | null;
@@ -127,6 +130,9 @@ export interface Page {
layout: (CallToActionBlock | ContentBlock | MediaBlock | ArchiveBlock | FormBlock)[];
meta?: {
title?: string | null;
/**
* Maximum upload file size: 12MB. Recommended file size for images is <500KB.
*/
image?: (number | null) | Media;
description?: string | null;
};
@@ -164,6 +170,9 @@ export interface Post {
categories?: (number | Category)[] | null;
meta?: {
title?: string | null;
/**
* Maximum upload file size: 12MB. Recommended file size for images is <500KB.
*/
image?: (number | null) | Media;
description?: string | null;
};
@@ -280,6 +289,8 @@ export interface Media {
export interface Category {
id: number;
title: string;
slug?: string | null;
slugLock?: boolean | null;
parent?: (number | null) | Category;
breadcrumbs?:
| {
@@ -346,6 +357,9 @@ export interface CallToActionBlock {
} | null);
url?: string | null;
label: string;
/**
* Choose how the link should be rendered.
*/
appearance?: ('default' | 'outline') | null;
};
id?: string | null;
@@ -393,6 +407,9 @@ export interface ContentBlock {
} | null);
url?: string | null;
label: string;
/**
* Choose how the link should be rendered.
*/
appearance?: ('default' | 'outline') | null;
};
id?: string | null;
@@ -588,6 +605,9 @@ export interface Form {
)[]
| null;
submitButtonLabel?: string | null;
/**
* Choose whether to display an on-page message or redirect to a different page after they submit the form.
*/
confirmationType?: ('message' | 'redirect') | null;
confirmationMessage?: {
root: {
@@ -607,6 +627,9 @@ export interface Form {
redirect?: {
url: string;
};
/**
* Send custom emails when the form submits. Use comma separated lists to send the same email to multiple recipients. To reference a value from this form, wrap that field's name with double curly brackets, i.e. {{firstName}}. You can use a wildcard {{*}} to output all data and {{*:table}} to format it as an HTML table in the email.
*/
emails?:
| {
emailTo?: string | null;
@@ -615,6 +638,9 @@ export interface Form {
replyTo?: string | null;
emailFrom?: string | null;
subject: string;
/**
* Enter the message that should be sent in this email.
*/
message?: {
root: {
type: string;
@@ -642,6 +668,9 @@ export interface Form {
*/
export interface Redirect {
id: number;
/**
* You will need to rebuild the website when changing this field.
*/
from: string;
to?: {
type?: ('reference' | 'custom') | null;
@@ -677,6 +706,8 @@ export interface FormSubmission {
createdAt: string;
}
/**
* This is a collection of automatically created search results. These results are used by the global site search and will be updated automatically as documents in the CMS are created or updated.
*
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "search".
*/
@@ -820,80 +851,11 @@ export interface PagesSelect<T extends boolean = true> {
layout?:
| T
| {
cta?:
| T
| {
richText?: T;
links?:
| T
| {
link?:
| T
| {
type?: T;
newTab?: T;
reference?: T;
url?: T;
label?: T;
appearance?: T;
};
id?: T;
};
id?: T;
blockName?: T;
};
content?:
| T
| {
columns?:
| T
| {
size?: T;
richText?: T;
enableLink?: T;
link?:
| T
| {
type?: T;
newTab?: T;
reference?: T;
url?: T;
label?: T;
appearance?: T;
};
id?: T;
};
id?: T;
blockName?: T;
};
mediaBlock?:
| T
| {
media?: T;
id?: T;
blockName?: T;
};
archive?:
| T
| {
introContent?: T;
populateBy?: T;
relationTo?: T;
categories?: T;
limit?: T;
selectedDocs?: T;
id?: T;
blockName?: T;
};
formBlock?:
| T
| {
form?: T;
enableIntro?: T;
introContent?: T;
id?: T;
blockName?: T;
};
cta?: T | CallToActionBlockSelect<T>;
content?: T | ContentBlockSelect<T>;
mediaBlock?: T | MediaBlockSelect<T>;
archive?: T | ArchiveBlockSelect<T>;
formBlock?: T | FormBlockSelect<T>;
};
meta?:
| T
@@ -909,6 +871,90 @@ export interface PagesSelect<T extends boolean = true> {
createdAt?: T;
_status?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "CallToActionBlock_select".
*/
export interface CallToActionBlockSelect<T extends boolean = true> {
richText?: T;
links?:
| T
| {
link?:
| T
| {
type?: T;
newTab?: T;
reference?: T;
url?: T;
label?: T;
appearance?: T;
};
id?: T;
};
id?: T;
blockName?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "ContentBlock_select".
*/
export interface ContentBlockSelect<T extends boolean = true> {
columns?:
| T
| {
size?: T;
richText?: T;
enableLink?: T;
link?:
| T
| {
type?: T;
newTab?: T;
reference?: T;
url?: T;
label?: T;
appearance?: T;
};
id?: T;
};
id?: T;
blockName?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "MediaBlock_select".
*/
export interface MediaBlockSelect<T extends boolean = true> {
media?: T;
id?: T;
blockName?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "ArchiveBlock_select".
*/
export interface ArchiveBlockSelect<T extends boolean = true> {
introContent?: T;
populateBy?: T;
relationTo?: T;
categories?: T;
limit?: T;
selectedDocs?: T;
id?: T;
blockName?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "FormBlock_select".
*/
export interface FormBlockSelect<T extends boolean = true> {
form?: T;
enableIntro?: T;
introContent?: T;
id?: T;
blockName?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts_select".
@@ -1039,6 +1085,8 @@ export interface MediaSelect<T extends boolean = true> {
*/
export interface CategoriesSelect<T extends boolean = true> {
title?: T;
slug?: T;
slugLock?: T;
parent?: T;
breadcrumbs?:
| T

View File

@@ -49,6 +49,7 @@ export const plugins: Plugin[] = [
}),
nestedDocsPlugin({
collections: ['categories'],
generateURL: (docs) => docs.reduce((url, doc) => `${url}/${doc.slug}`, ''),
}),
seoPlugin({
generateTitle,