Skip to content

Commit 9866af7

Browse files
slorberthadguidry
andauthored
feat(pages): add support for missing SEO front matter + improve SEO docs (#9071)
Co-authored-by: Thad Guidry <thadguidry@gmail.com>
1 parent 117cbac commit 9866af7

11 files changed

Lines changed: 146 additions & 22 deletions

File tree

packages/docusaurus-plugin-content-pages/src/frontMatter.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,24 @@ import {
1010
validateFrontMatter,
1111
FrontMatterTOCHeadingLevels,
1212
ContentVisibilitySchema,
13+
URISchema,
1314
} from '@docusaurus/utils-validation';
14-
import type {FrontMatter} from '@docusaurus/plugin-content-pages';
15+
import type {PageFrontMatter} from '@docusaurus/plugin-content-pages';
1516

16-
const PageFrontMatterSchema = Joi.object<FrontMatter>({
17-
title: Joi.string(),
18-
description: Joi.string(),
17+
const PageFrontMatterSchema = Joi.object<PageFrontMatter>({
18+
// See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
19+
title: Joi.string().allow(''),
20+
// See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398
21+
description: Joi.string().allow(''),
22+
keywords: Joi.array().items(Joi.string().required()),
23+
image: URISchema,
1924
wrapperClassName: Joi.string(),
2025
hide_table_of_contents: Joi.boolean(),
2126
...FrontMatterTOCHeadingLevels,
2227
}).concat(ContentVisibilitySchema);
2328

2429
export function validatePageFrontMatter(frontMatter: {
2530
[key: string]: unknown;
26-
}): FrontMatter {
31+
}): PageFrontMatter {
2732
return validateFrontMatter(frontMatter, PageFrontMatterSchema);
2833
}

packages/docusaurus-plugin-content-pages/src/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import type {
3131
PluginOptions,
3232
Metadata,
3333
LoadedContent,
34+
PageFrontMatter,
3435
} from '@docusaurus/plugin-content-pages';
3536

3637
export function getContentPathList(contentPaths: PagesContentPaths): string[] {
@@ -234,6 +235,15 @@ export default function pluginContentPages(
234235
`${docuHash(aliasedSource)}.json`,
235236
);
236237
},
238+
// Assets allow to convert some relative images paths to
239+
// require(...) calls
240+
createAssets: ({
241+
frontMatter,
242+
}: {
243+
frontMatter: PageFrontMatter;
244+
}) => ({
245+
image: frontMatter.image,
246+
}),
237247
markdownConfig: siteConfig.markdown,
238248
},
239249
},

packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ declare module '@docusaurus/plugin-content-pages' {
99
import type {MDXOptions} from '@docusaurus/mdx-loader';
1010
import type {LoadContext, Plugin} from '@docusaurus/types';
1111

12+
export type Assets = {
13+
image?: string;
14+
};
15+
1216
export type PluginOptions = MDXOptions & {
1317
id?: string;
1418
path: string;
@@ -20,9 +24,11 @@ declare module '@docusaurus/plugin-content-pages' {
2024

2125
export type Options = Partial<PluginOptions>;
2226

23-
export type FrontMatter = {
27+
export type PageFrontMatter = {
2428
readonly title?: string;
2529
readonly description?: string;
30+
readonly image?: string;
31+
readonly keywords?: string[];
2632
readonly wrapperClassName?: string;
2733
readonly hide_table_of_contents?: string;
2834
readonly toc_min_heading_level?: number;
@@ -41,7 +47,7 @@ declare module '@docusaurus/plugin-content-pages' {
4147
type: 'mdx';
4248
permalink: string;
4349
source: string;
44-
frontMatter: FrontMatter & {[key: string]: unknown};
50+
frontMatter: PageFrontMatter & {[key: string]: unknown};
4551
title?: string;
4652
description?: string;
4753
unlisted: boolean;
@@ -61,11 +67,16 @@ declare module '@theme/MDXPage' {
6167
import type {LoadedMDXContent} from '@docusaurus/mdx-loader';
6268
import type {
6369
MDXPageMetadata,
64-
FrontMatter,
70+
PageFrontMatter,
71+
Assets,
6572
} from '@docusaurus/plugin-content-pages';
6673

6774
export interface Props {
68-
readonly content: LoadedMDXContent<FrontMatter, MDXPageMetadata>;
75+
readonly content: LoadedMDXContent<
76+
PageFrontMatter,
77+
MDXPageMetadata,
78+
Assets
79+
>;
6980
}
7081

7182
export default function MDXPage(props: Props): JSX.Element;

packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,28 @@ export default function MDXPage(props: Props): JSX.Element {
2424
const {content: MDXPageContent} = props;
2525
const {
2626
metadata: {title, description, frontMatter, unlisted},
27+
assets,
2728
} = MDXPageContent;
28-
const {wrapperClassName, hide_table_of_contents: hideTableOfContents} =
29-
frontMatter;
29+
const {
30+
keywords,
31+
wrapperClassName,
32+
hide_table_of_contents: hideTableOfContents,
33+
} = frontMatter;
34+
const image = assets.image ?? frontMatter.image;
3035

3136
return (
3237
<HtmlClassNameProvider
3338
className={clsx(
3439
wrapperClassName ?? ThemeClassNames.wrapper.mdxPages,
3540
ThemeClassNames.page.mdxPage,
3641
)}>
37-
<PageMetadata title={title} description={description} />
3842
<Layout>
43+
<PageMetadata
44+
title={title}
45+
description={description}
46+
keywords={keywords}
47+
image={image}
48+
/>
3949
<main className="container container--fluid margin-vert--lg">
4050
<div className={clsx('row', styles.mdxPageWrapper)}>
4151
<div className={clsx('col', !hideTableOfContents && 'col--8')}>
6.96 KB
Loading
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
title: custom SEO title
3+
description: custom SEO description
4+
keywords: [custom, keywords]
5+
image: ./local-image.png
6+
---
7+
8+
# SEO tests
9+
10+
Using page SEO front matter:
11+
12+
```yaml
13+
title: custom SEO title
14+
description: custom SEO description
15+
keywords: [custom, keywords]
16+
image: ./local-image.png
17+
```

website/docs/api/plugins/plugin-content-blog.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ const config = {
194194

195195
## Markdown front matter {#markdown-front-matter}
196196

197-
Markdown documents can use the following Markdown front matter metadata fields, enclosed by a line `---` on either side.
197+
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.
198198

199199
Accepted fields:
200200

website/docs/api/plugins/plugin-content-docs.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ const config = {
261261

262262
## Markdown front matter {#markdown-front-matter}
263263

264-
Markdown documents can use the following Markdown front matter metadata fields, enclosed by a line `---` on either side.
264+
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.
265265

266266
Accepted fields:
267267

website/docs/api/plugins/plugin-content-pages.mdx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ const config = {
8181

8282
## Markdown front matter {#markdown-front-matter}
8383

84-
Markdown pages can use the following Markdown front matter metadata fields, enclosed by a line `---` on either side.
84+
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.
8585

8686
Accepted fields:
8787

@@ -93,7 +93,9 @@ Accepted fields:
9393
| --- | --- | --- | --- |
9494
| `title` | `string` | Markdown title | The blog post title. |
9595
| `description` | `string` | The first line of Markdown content | The description of your page, which will become the `<meta name="description" content="..."/>` and `<meta property="og:description" content="..."/>` in `<head>`, used by search engines. |
96-
| `wrapperClassName` | `string` | Class name to be added to the wrapper element to allow targeting specific page content. |
96+
| `keywords` | `string[]` | `undefined` | Keywords meta tag, which will become the `<meta name="keywords" content="keyword1,keyword2,..."/>` in `<head>`, used by search engines. |
97+
| `image` | `string` | `undefined` | Cover or thumbnail image that will be used when displaying the link to your post. |
98+
| `wrapperClassName` | `string` | | Class name to be added to the wrapper element to allow targeting specific page content. |
9799
| `hide_table_of_contents` | `boolean` | `false` | Whether to hide the table of contents to the right. |
98100
| `draft` | `boolean` | `false` | Draft pages will only be available during development. |
99101
| `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. |

website/docs/guides/markdown-features/markdown-features-intro.mdx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,16 @@ more_data:
7272
---
7373
```
7474

75+
:::info
76+
77+
The API documentation of each official plugin lists the supported attributes:
78+
79+
- [Docs front matter](../../api/plugins/plugin-content-docs.mdx#markdown-front-matter)
80+
- [Blog front matter](../../api/plugins/plugin-content-blog.mdx#markdown-front-matter)
81+
- [Pages front matter](../../api/plugins/plugin-content-pages.mdx#markdown-front-matter)
82+
83+
:::
84+
7585
## Quotes {#quotes}
7686

7787
Markdown quotes are beautifully styled:

0 commit comments

Comments
 (0)