diff --git a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts index 87562de53e..b87907adbd 100644 --- a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts @@ -10,12 +10,17 @@ import { validateFrontMatter, FrontMatterTOCHeadingLevels, ContentVisibilitySchema, + URISchema, } from '@docusaurus/utils-validation'; -import type {FrontMatter} from '@docusaurus/plugin-content-pages'; +import type {PageFrontMatter} from '@docusaurus/plugin-content-pages'; -const PageFrontMatterSchema = Joi.object({ - title: Joi.string(), - description: Joi.string(), +const PageFrontMatterSchema = Joi.object({ + // See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398 + title: Joi.string().allow(''), + // See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398 + description: Joi.string().allow(''), + keywords: Joi.array().items(Joi.string().required()), + image: URISchema, wrapperClassName: Joi.string(), hide_table_of_contents: Joi.boolean(), ...FrontMatterTOCHeadingLevels, @@ -23,6 +28,6 @@ const PageFrontMatterSchema = Joi.object({ export function validatePageFrontMatter(frontMatter: { [key: string]: unknown; -}): FrontMatter { +}): PageFrontMatter { return validateFrontMatter(frontMatter, PageFrontMatterSchema); } diff --git a/packages/docusaurus-plugin-content-pages/src/index.ts b/packages/docusaurus-plugin-content-pages/src/index.ts index f65cd49a18..e62d07c6cb 100644 --- a/packages/docusaurus-plugin-content-pages/src/index.ts +++ b/packages/docusaurus-plugin-content-pages/src/index.ts @@ -31,6 +31,7 @@ import type { PluginOptions, Metadata, LoadedContent, + PageFrontMatter, } from '@docusaurus/plugin-content-pages'; export function getContentPathList(contentPaths: PagesContentPaths): string[] { @@ -234,6 +235,15 @@ export default function pluginContentPages( `${docuHash(aliasedSource)}.json`, ); }, + // Assets allow to convert some relative images paths to + // require(...) calls + createAssets: ({ + frontMatter, + }: { + frontMatter: PageFrontMatter; + }) => ({ + image: frontMatter.image, + }), markdownConfig: siteConfig.markdown, }, }, 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 0927982839..f0a9230cde 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 @@ -9,6 +9,10 @@ declare module '@docusaurus/plugin-content-pages' { import type {MDXOptions} from '@docusaurus/mdx-loader'; import type {LoadContext, Plugin} from '@docusaurus/types'; + export type Assets = { + image?: string; + }; + export type PluginOptions = MDXOptions & { id?: string; path: string; @@ -20,9 +24,11 @@ declare module '@docusaurus/plugin-content-pages' { export type Options = Partial; - export type FrontMatter = { + export type PageFrontMatter = { readonly title?: string; readonly description?: string; + readonly image?: string; + readonly keywords?: string[]; readonly wrapperClassName?: string; readonly hide_table_of_contents?: string; readonly toc_min_heading_level?: number; @@ -41,7 +47,7 @@ declare module '@docusaurus/plugin-content-pages' { type: 'mdx'; permalink: string; source: string; - frontMatter: FrontMatter & {[key: string]: unknown}; + frontMatter: PageFrontMatter & {[key: string]: unknown}; title?: string; description?: string; unlisted: boolean; @@ -61,11 +67,16 @@ declare module '@theme/MDXPage' { import type {LoadedMDXContent} from '@docusaurus/mdx-loader'; import type { MDXPageMetadata, - FrontMatter, + PageFrontMatter, + Assets, } from '@docusaurus/plugin-content-pages'; export interface Props { - readonly content: LoadedMDXContent; + readonly content: LoadedMDXContent< + PageFrontMatter, + MDXPageMetadata, + Assets + >; } export default function MDXPage(props: Props): JSX.Element; diff --git a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx index 6d865b91ea..c9222ad0b5 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx @@ -24,9 +24,14 @@ export default function MDXPage(props: Props): JSX.Element { const {content: MDXPageContent} = props; const { metadata: {title, description, frontMatter, unlisted}, + assets, } = MDXPageContent; - const {wrapperClassName, hide_table_of_contents: hideTableOfContents} = - frontMatter; + const { + keywords, + wrapperClassName, + hide_table_of_contents: hideTableOfContents, + } = frontMatter; + const image = assets.image ?? frontMatter.image; return ( - +
diff --git a/website/_dogfooding/_pages tests/local-image.png b/website/_dogfooding/_pages tests/local-image.png new file mode 100644 index 0000000000..0b1e98a2f0 Binary files /dev/null and b/website/_dogfooding/_pages tests/local-image.png differ diff --git a/website/_dogfooding/_pages tests/seo.md b/website/_dogfooding/_pages tests/seo.md new file mode 100644 index 0000000000..dd6a1903ff --- /dev/null +++ b/website/_dogfooding/_pages tests/seo.md @@ -0,0 +1,17 @@ +--- +title: custom SEO title +description: custom SEO description +keywords: [custom, keywords] +image: ./local-image.png +--- + +# SEO tests + +Using page SEO front matter: + +```yaml +title: custom SEO title +description: custom SEO description +keywords: [custom, keywords] +image: ./local-image.png +``` diff --git a/website/docs/api/plugins/plugin-content-blog.mdx b/website/docs/api/plugins/plugin-content-blog.mdx index 68c0515dff..52212f8b56 100644 --- a/website/docs/api/plugins/plugin-content-blog.mdx +++ b/website/docs/api/plugins/plugin-content-blog.mdx @@ -194,7 +194,7 @@ const config = { ## Markdown front matter {#markdown-front-matter} -Markdown documents can use the following Markdown front matter metadata fields, enclosed by a line `---` on either side. +Markdown documents can use the following Markdown [front matter](../../guides/markdown-features/markdown-features-intro.mdx#front-matter) metadata fields, enclosed by a line `---` on either side. Accepted fields: diff --git a/website/docs/api/plugins/plugin-content-docs.mdx b/website/docs/api/plugins/plugin-content-docs.mdx index 8a731e4b6a..31a44f221e 100644 --- a/website/docs/api/plugins/plugin-content-docs.mdx +++ b/website/docs/api/plugins/plugin-content-docs.mdx @@ -261,7 +261,7 @@ const config = { ## Markdown front matter {#markdown-front-matter} -Markdown documents can use the following Markdown front matter metadata fields, enclosed by a line `---` on either side. +Markdown documents can use the following Markdown [front matter](../../guides/markdown-features/markdown-features-intro.mdx#front-matter) metadata fields, enclosed by a line `---` on either side. Accepted fields: diff --git a/website/docs/api/plugins/plugin-content-pages.mdx b/website/docs/api/plugins/plugin-content-pages.mdx index eaefe2ff8d..d2976d0fbb 100644 --- a/website/docs/api/plugins/plugin-content-pages.mdx +++ b/website/docs/api/plugins/plugin-content-pages.mdx @@ -81,7 +81,7 @@ const config = { ## Markdown front matter {#markdown-front-matter} -Markdown pages can use the following Markdown front matter metadata fields, enclosed by a line `---` on either side. +Markdown pages can use the following Markdown [front matter](../../guides/markdown-features/markdown-features-intro.mdx#front-matter) metadata fields, enclosed by a line `---` on either side. Accepted fields: @@ -93,7 +93,9 @@ Accepted fields: | --- | --- | --- | --- | | `title` | `string` | Markdown title | The blog post title. | | `description` | `string` | The first line of Markdown content | The description of your page, which will become the `` and `` in ``, used by search engines. | -| `wrapperClassName` | `string` | Class name to be added to the wrapper element to allow targeting specific page content. | +| `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 when displaying the link to your post. | +| `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. | | `unlisted` | `boolean` | `false` | Unlisted pages will be available in both development and production. They will be "hidden" in production, not indexed, excluded from sitemaps, and can only be accessed by users having a direct link. | diff --git a/website/docs/guides/markdown-features/markdown-features-intro.mdx b/website/docs/guides/markdown-features/markdown-features-intro.mdx index 30212e5004..2da4138783 100644 --- a/website/docs/guides/markdown-features/markdown-features-intro.mdx +++ b/website/docs/guides/markdown-features/markdown-features-intro.mdx @@ -72,6 +72,16 @@ more_data: --- ``` +:::info + +The API documentation of each official plugin lists the supported attributes: + +- [Docs front matter](../../api/plugins/plugin-content-docs.mdx#markdown-front-matter) +- [Blog front matter](../../api/plugins/plugin-content-blog.mdx#markdown-front-matter) +- [Pages front matter](../../api/plugins/plugin-content-pages.mdx#markdown-front-matter) + +::: + ## Quotes {#quotes} Markdown quotes are beautifully styled: diff --git a/website/docs/seo.mdx b/website/docs/seo.mdx index a16d3a80d9..048a23a668 100644 --- a/website/docs/seo.mdx +++ b/website/docs/seo.mdx @@ -14,13 +14,40 @@ Docusaurus supports search engine optimization in a variety of ways. ## Global metadata {#global-metadata} -Provide global meta attributes for the entire site through the [site configuration](./configuration.mdx#site-metadata). The metadata will all be rendered in the HTML `` using the key-value pairs as the prop name and value. +Provide global meta attributes for the entire site through the [site configuration](./configuration.mdx#site-metadata). The metadata will all be rendered in the HTML `` using the key-value pairs as the prop name and value. The `metadata` attribute is a convenient shortcut to declare `` tags, but it is also possible to inject arbitrary tags in `` with the `headTags` attribute. ```js title="docusaurus.config.js" module.exports = { themeConfig: { - metadata: [{name: 'keywords', content: 'cooking, blog'}], - // This would become in the generated HTML + // Declare some tags + metadata: [ + {name: 'keywords', content: 'cooking, blog'}, + {name: 'twitter:card', content: 'summary_large_image'}, + ], + headTags: [ + // Declare a preconnect tag + { + tagName: 'link', + attributes: { + rel: 'preconnect', + href: 'https://example.com', + }, + }, + // Declare some json-ld structured data + { + tagName: 'script', + attributes: { + type: 'application/ld+json', + }, + innerHTML: JSON.stringify({ + '@context': 'https://schema.org/', + '@type': 'Organization', + name: 'Meta Open Source', + url: 'https://opensource.fb.com/', + logo: 'https://opensource.fb.com/img/logos/Meta-Open-Source.svg', + }), + }, + ], }, }; ``` @@ -37,13 +64,24 @@ Similar to [global metadata](#global-metadata), Docusaurus also allows for the a # A cooking guide - + + + + Some content... ``` -Docusaurus automatically adds `description`, `title`, canonical URL links, and other useful metadata to each Markdown page. They are configurable through front matter: +Docusaurus automatically adds `description`, `title`, canonical URL links, and other useful metadata to each Markdown page. They are configurable through [front matter](./guides/markdown-features/markdown-features-intro.mdx#front-matter): ```md --- @@ -58,7 +96,17 @@ When creating your React page, adding these fields in `Layout` would also improv :::tip -Prefer to use front matter for fields like `description` and `keywords`: Docusaurus will automatically apply this to both `description` and `og:description`, while you would have to manually declare two metadata tags when using the `` tag. +Prefer to use [front matter](./guides/markdown-features/markdown-features-intro.mdx#front-matter) for fields like `description` and `keywords`: Docusaurus will automatically apply this to both `description` and `og:description`, while you would have to manually declare two metadata tags when using the `` tag. + +::: + +:::info + +The official plugins all support the following [front matter](./guides/markdown-features/markdown-features-intro.mdx#front-matter): `title`, `description`, `keywords` and `image`. Refer to their respective API documentation for additional [front matter](./guides/markdown-features/markdown-features-intro.mdx#front-matter) support: + +- [Docs front matter](./api/plugins/plugin-content-docs.mdx#markdown-front-matter) +- [Blog front matter](./api/plugins/plugin-content-blog.mdx#markdown-front-matter) +- [Pages front matter](./api/plugins/plugin-content-pages.mdx#markdown-front-matter) ::: @@ -74,6 +122,17 @@ export default function page() { + + + {/* ... */}