diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/__fixtures__/website/src/pages/hello/mdxPage.mdx b/packages/docusaurus-plugin-content-pages/src/__tests__/__fixtures__/website/src/pages/hello/mdxPage.mdx index 27b0b9f9be..79a1fc5af9 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/__fixtures__/website/src/pages/hello/mdxPage.mdx +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/__fixtures__/website/src/pages/hello/mdxPage.mdx @@ -1,5 +1,7 @@ --- title: MDX page description: my MDX page +slug: /custom-mdx/slug --- + MDX page diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap index bc9b5308c3..ecb51dba22 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap @@ -32,11 +32,12 @@ exports[`docusaurus-plugin-content-pages loads simple pages 1`] = ` "frontMatter": { "custom_frontMatter": "added by parseFrontMatter", "description": "my MDX page", + "slug": "/custom-mdx/slug", "title": "MDX page", }, "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "permalink": "/hello/mdxPage", + "permalink": "/custom-mdx/slug", "source": "@site/src/pages/hello/mdxPage.mdx", "title": "MDX page", "type": "mdx", @@ -101,11 +102,12 @@ exports[`docusaurus-plugin-content-pages loads simple pages with french translat "frontMatter": { "custom_frontMatter": "added by parseFrontMatter", "description": "my MDX page", + "slug": "/custom-mdx/slug", "title": "MDX page", }, "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, - "permalink": "/fr/hello/mdxPage", + "permalink": "/fr/custom-mdx/slug", "source": "@site/src/pages/hello/mdxPage.mdx", "title": "MDX page", "type": "mdx", @@ -170,11 +172,12 @@ exports[`docusaurus-plugin-content-pages loads simple pages with last update 1`] "frontMatter": { "custom_frontMatter": "added by parseFrontMatter", "description": "my MDX page", + "slug": "/custom-mdx/slug", "title": "MDX page", }, "lastUpdatedAt": 1539502055000, "lastUpdatedBy": "Author", - "permalink": "/hello/mdxPage", + "permalink": "/custom-mdx/slug", "source": "@site/src/pages/hello/mdxPage.mdx", "title": "MDX page", "type": "mdx", diff --git a/packages/docusaurus-plugin-content-pages/src/content.ts b/packages/docusaurus-plugin-content-pages/src/content.ts index 769adbf459..97806bfb67 100644 --- a/packages/docusaurus-plugin-content-pages/src/content.ts +++ b/packages/docusaurus-plugin-content-pages/src/content.ts @@ -106,12 +106,13 @@ async function processPageSourceFile( const source = path.join(contentPath, relativeSource); const aliasedSourcePath = aliasedSitePath(source, siteDir); - const permalink = normalizeUrl([ - baseUrl, - options.routeBasePath, - encodePath(fileToPath(relativeSource)), - ]); + + const filenameSlug = encodePath(fileToPath(relativeSource)); + if (!isMarkdownSource(relativeSource)) { + // For now, slug can't be customized for JSX pages + const slug = filenameSlug; + const permalink = normalizeUrl([baseUrl, options.routeBasePath, slug]); return { type: 'jsx', permalink, @@ -131,6 +132,9 @@ async function processPageSourceFile( }); const frontMatter = validatePageFrontMatter(unsafeFrontMatter); + const slug = frontMatter.slug ?? filenameSlug; + const permalink = normalizeUrl([baseUrl, options.routeBasePath, slug]); + const pagesDirPath = await getFolderContainingFile( getContentPathList(contentPaths), relativeSource, diff --git a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts index 5a87b1a221..d68923d89e 100644 --- a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts @@ -22,6 +22,7 @@ const PageFrontMatterSchema = Joi.object({ description: Joi.string().allow(''), keywords: Joi.array().items(Joi.string().required()), image: URISchema, + slug: Joi.string(), wrapperClassName: Joi.string(), hide_table_of_contents: Joi.boolean(), ...FrontMatterTOCHeadingLevels, diff --git a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts index d9045fd3f4..c0e02f40ae 100644 --- a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts +++ b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts @@ -37,6 +37,7 @@ declare module '@docusaurus/plugin-content-pages' { readonly title?: string; readonly description?: string; readonly image?: string; + readonly slug?: string; readonly keywords?: string[]; readonly wrapperClassName?: string; readonly hide_table_of_contents?: string; diff --git a/website/_dogfooding/_pages tests/index.mdx b/website/_dogfooding/_pages tests/index.mdx index 6ed5de6daf..38f13ae9ae 100644 --- a/website/_dogfooding/_pages tests/index.mdx +++ b/website/_dogfooding/_pages tests/index.mdx @@ -37,7 +37,7 @@ import Readme from "../README.mdx" - [Tabs tests](/tests/pages/tabs-tests) - [z-index tests](/tests/pages/z-index-tests) - [Head metadata tests](/tests/pages/head-metadata) -- [Unlisted page](/tests/pages/unlisted) +- [Unlisted page](/tests/pages/my-custom/unlisted/slug) - [Analytics](/tests/pages/analytics) - [History tests](/tests/pages/history-tests) - [Embeds](/tests/pages/embeds) diff --git a/website/_dogfooding/_pages tests/unlisted.mdx b/website/_dogfooding/_pages tests/unlisted.mdx index 0e34391496..f1a0134320 100644 --- a/website/_dogfooding/_pages tests/unlisted.mdx +++ b/website/_dogfooding/_pages tests/unlisted.mdx @@ -1,5 +1,6 @@ --- unlisted: true +slug: /my-custom/unlisted/slug --- # Unlisted page diff --git a/website/docs/api/plugins/plugin-content-pages.mdx b/website/docs/api/plugins/plugin-content-pages.mdx index 03db1f4f1b..b71ef05500 100644 --- a/website/docs/api/plugins/plugin-content-pages.mdx +++ b/website/docs/api/plugins/plugin-content-pages.mdx @@ -113,6 +113,7 @@ Accepted fields: | `description` | `string` | The first line of Markdown content | The description of your page, which will become the `` and `` in ``, used by search engines. | | `keywords` | `string[]` | `undefined` | Keywords meta tag, which will become the `` in ``, used by search engines. | | `image` | `string` | `undefined` | Cover or thumbnail image that will be used as the `` in the ``, enhancing link previews on social media and messaging platforms. | +| `slug` | `string` | File path | Allows to customize the page URL (`//`). Support multiple patterns: `slug: my-page`, `slug: /my/page`, slug: `/`. | | `wrapperClassName` | `string` | | Class name to be added to the wrapper element to allow targeting specific page content. | | `hide_table_of_contents` | `boolean` | `false` | Whether to hide the table of contents to the right. | | `draft` | `boolean` | `false` | Draft pages will only be available during development. | @@ -131,6 +132,7 @@ description: Markdown page SEO description wrapperClassName: markdown-page hide_table_of_contents: false draft: true +slug: /markdown-page --- Markdown page content