mirror of
https://github.com/facebook/docusaurus.git
synced 2025-08-06 10:20:09 +02:00
refactor: add blog microdata in markup instead of use JSON-LD (#5355)
* refactor: add blog microdata in markup intead of use JSON-LD * Add check for authorTitle
This commit is contained in:
parent
09a954165c
commit
ee6882650e
5 changed files with 51 additions and 87 deletions
|
@ -31,7 +31,9 @@ function BlogLayout(props: Props): JSX.Element {
|
||||||
className={clsx('col', {
|
className={clsx('col', {
|
||||||
'col--7': hasSidebar,
|
'col--7': hasSidebar,
|
||||||
'col--9 col--offset-1': !hasSidebar,
|
'col--9 col--offset-1': !hasSidebar,
|
||||||
})}>
|
})}
|
||||||
|
itemScope
|
||||||
|
itemType="http://schema.org/Blog">
|
||||||
{children}
|
{children}
|
||||||
</main>
|
</main>
|
||||||
{toc && (
|
{toc && (
|
||||||
|
|
|
@ -10,6 +10,7 @@ import clsx from 'clsx';
|
||||||
import {MDXProvider} from '@mdx-js/react';
|
import {MDXProvider} from '@mdx-js/react';
|
||||||
import Translate, {translate} from '@docusaurus/Translate';
|
import Translate, {translate} from '@docusaurus/Translate';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
|
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
|
||||||
import {usePluralForm} from '@docusaurus/theme-common';
|
import {usePluralForm} from '@docusaurus/theme-common';
|
||||||
import MDXComponents from '@theme/MDXComponents';
|
import MDXComponents from '@theme/MDXComponents';
|
||||||
import Seo from '@theme/Seo';
|
import Seo from '@theme/Seo';
|
||||||
|
@ -40,6 +41,7 @@ function useReadingTimePlural() {
|
||||||
|
|
||||||
function BlogPostItem(props: Props): JSX.Element {
|
function BlogPostItem(props: Props): JSX.Element {
|
||||||
const readingTimePlural = useReadingTimePlural();
|
const readingTimePlural = useReadingTimePlural();
|
||||||
|
const {withBaseUrl} = useBaseUrlUtils();
|
||||||
const {
|
const {
|
||||||
children,
|
children,
|
||||||
frontMatter,
|
frontMatter,
|
||||||
|
@ -74,11 +76,19 @@ function BlogPostItem(props: Props): JSX.Element {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header>
|
<header>
|
||||||
<TitleHeading className={styles.blogPostTitle}>
|
<TitleHeading className={styles.blogPostTitle} itemProp="headline">
|
||||||
{isBlogPostPage ? title : <Link to={permalink}>{title}</Link>}
|
{isBlogPostPage ? (
|
||||||
|
title
|
||||||
|
) : (
|
||||||
|
<Link itemProp="url" to={permalink}>
|
||||||
|
{title}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
</TitleHeading>
|
</TitleHeading>
|
||||||
<div className={clsx(styles.blogPostData, 'margin-vert--md')}>
|
<div className={clsx(styles.blogPostData, 'margin-vert--md')}>
|
||||||
<time dateTime={date}>{formattedDate}</time>
|
<time dateTime={date} itemProp="datePublished">
|
||||||
|
{formattedDate}
|
||||||
|
</time>
|
||||||
|
|
||||||
{readingTime && (
|
{readingTime && (
|
||||||
<>
|
<>
|
||||||
|
@ -93,16 +103,25 @@ function BlogPostItem(props: Props): JSX.Element {
|
||||||
<img src={authorImageURL} alt={author} />
|
<img src={authorImageURL} alt={author} />
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
<div className="avatar__intro">
|
{author && (
|
||||||
{author && (
|
<div
|
||||||
<>
|
className="avatar__intro"
|
||||||
<div className="avatar__name">
|
itemProp="author"
|
||||||
<Link href={authorURL}>{author}</Link>
|
itemScope
|
||||||
</div>
|
itemType="https://schema.org/Person">
|
||||||
<small className="avatar__subtitle">{authorTitle}</small>
|
<div className="avatar__name">
|
||||||
</>
|
<Link href={authorURL} itemProp="url">
|
||||||
)}
|
<span itemProp="name">{author}</span>
|
||||||
</div>
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{authorTitle && (
|
||||||
|
<small className="avatar__subtitle" itemProp="description">
|
||||||
|
{authorTitle}
|
||||||
|
</small>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
|
@ -112,11 +131,24 @@ function BlogPostItem(props: Props): JSX.Element {
|
||||||
<>
|
<>
|
||||||
<Seo {...{keywords, image}} />
|
<Seo {...{keywords, image}} />
|
||||||
|
|
||||||
<article className={!isBlogPostPage ? 'margin-bottom--xl' : undefined}>
|
<article
|
||||||
|
className={!isBlogPostPage ? 'margin-bottom--xl' : undefined}
|
||||||
|
itemProp="blogPost"
|
||||||
|
itemScope
|
||||||
|
itemType="http://schema.org/BlogPosting">
|
||||||
{renderPostHeader()}
|
{renderPostHeader()}
|
||||||
<div className="markdown">
|
|
||||||
|
{image && (
|
||||||
|
<meta
|
||||||
|
itemProp="image"
|
||||||
|
content={withBaseUrl(image, {absolute: true})}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="markdown" itemProp="articleBody">
|
||||||
<MDXProvider components={MDXComponents}>{children}</MDXProvider>
|
<MDXProvider components={MDXComponents}>{children}</MDXProvider>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{(tags.length > 0 || truncated) && (
|
{(tags.length > 0 || truncated) && (
|
||||||
<footer
|
<footer
|
||||||
className={clsx('row docusaurus-mt-lg', {
|
className={clsx('row docusaurus-mt-lg', {
|
||||||
|
@ -131,6 +163,7 @@ function BlogPostItem(props: Props): JSX.Element {
|
||||||
Tags:
|
Tags:
|
||||||
</Translate>
|
</Translate>
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
{tags.map(({label, permalink: tagPermalink}) => (
|
{tags.map(({label, permalink: tagPermalink}) => (
|
||||||
<Link
|
<Link
|
||||||
key={tagPermalink}
|
key={tagPermalink}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import BlogLayout from '@theme/BlogLayout';
|
import BlogLayout from '@theme/BlogLayout';
|
||||||
import BlogPostItem from '@theme/BlogPostItem';
|
import BlogPostItem from '@theme/BlogPostItem';
|
||||||
import BlogPostStructuredData from '@theme/BlogPostStructuredData';
|
|
||||||
import BlogPostPaginator from '@theme/BlogPostPaginator';
|
import BlogPostPaginator from '@theme/BlogPostPaginator';
|
||||||
import type {Props} from '@theme/BlogPostPage';
|
import type {Props} from '@theme/BlogPostPage';
|
||||||
import {ThemeClassNames} from '@docusaurus/theme-common';
|
import {ThemeClassNames} from '@docusaurus/theme-common';
|
||||||
|
@ -31,11 +30,6 @@ function BlogPostPage(props: Props): JSX.Element {
|
||||||
? BlogPostContents.toc
|
? BlogPostContents.toc
|
||||||
: undefined
|
: undefined
|
||||||
}>
|
}>
|
||||||
<BlogPostStructuredData
|
|
||||||
frontMatter={frontMatter}
|
|
||||||
frontMatterAssets={frontMatterAssets}
|
|
||||||
metadata={metadata}
|
|
||||||
/>
|
|
||||||
<BlogPostItem
|
<BlogPostItem
|
||||||
frontMatter={frontMatter}
|
frontMatter={frontMatter}
|
||||||
frontMatterAssets={frontMatterAssets}
|
frontMatterAssets={frontMatterAssets}
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import Head from '@docusaurus/Head';
|
|
||||||
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
|
|
||||||
import type {Props} from '@theme/BlogPostStructuredData';
|
|
||||||
|
|
||||||
function BlogPostStructuredData(props: Props): JSX.Element {
|
|
||||||
const {withBaseUrl} = useBaseUrlUtils();
|
|
||||||
const {frontMatter, frontMatterAssets, metadata} = props;
|
|
||||||
const {date, title, description} = metadata;
|
|
||||||
|
|
||||||
const image = frontMatterAssets.image ?? frontMatter.image;
|
|
||||||
const {author} = frontMatter;
|
|
||||||
const authorURL = frontMatter.author_url || frontMatter.authorURL;
|
|
||||||
|
|
||||||
// details on structured data support: https://developers.google.com/search/docs/data-types/article#non-amp
|
|
||||||
// and https://schema.org/BlogPosting
|
|
||||||
const blogPostStructuredData = {
|
|
||||||
'@context': 'https://schema.org',
|
|
||||||
'@type': 'BlogPosting',
|
|
||||||
headline: title,
|
|
||||||
description,
|
|
||||||
...(image ? {image: [withBaseUrl(image, {absolute: true})]} : {}),
|
|
||||||
datePublished: date,
|
|
||||||
author: {
|
|
||||||
'@type': 'Person',
|
|
||||||
...(author ? {name: author} : {}),
|
|
||||||
url: authorURL,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Head>
|
|
||||||
<script type="application/ld+json">
|
|
||||||
{JSON.stringify(blogPostStructuredData)}
|
|
||||||
</script>
|
|
||||||
</Head>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default BlogPostStructuredData;
|
|
18
packages/docusaurus-theme-classic/src/types.d.ts
vendored
18
packages/docusaurus-theme-classic/src/types.d.ts
vendored
|
@ -46,24 +46,6 @@ declare module '@theme/BlogPostItem' {
|
||||||
export default BlogPostItem;
|
export default BlogPostItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/BlogPostStructuredData' {
|
|
||||||
import type {
|
|
||||||
FrontMatter,
|
|
||||||
FrontMatterAssets,
|
|
||||||
Metadata,
|
|
||||||
} from '@theme/BlogPostPage';
|
|
||||||
|
|
||||||
export type Props = {
|
|
||||||
readonly frontMatter: FrontMatter;
|
|
||||||
readonly frontMatterAssets: FrontMatterAssets;
|
|
||||||
readonly metadata: Metadata;
|
|
||||||
readonly truncated?: string | boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const BlogPostStructuredData: (props: Props) => JSX.Element;
|
|
||||||
export default BlogPostStructuredData;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '@theme/BlogPostPaginator' {
|
declare module '@theme/BlogPostPaginator' {
|
||||||
type Item = {readonly title: string; readonly permalink: string};
|
type Item = {readonly title: string; readonly permalink: string};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue