Skip to content

Commit 9511826

Browse files
committed
Refactor JSON-LD structured data handling in Docusaurus configuration and components
- Removed global JSON-LD structured data from docusaurus.config.js and updated comments to reflect per-page rendering. - Integrated structured data into CookbookDocItem and Layout components for improved SEO and compliance with JSON-LD audit recommendations.
1 parent 3f26bd7 commit 9511826

5 files changed

Lines changed: 120 additions & 41 deletions

File tree

docusaurus.config.js

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,46 +16,11 @@ module.exports = async function createConfigAsync() {
1616
favicon: 'favicon.ico',
1717
organizationName: 'temporalio', // Usually your GitHub org/user name.
1818
projectName: 'temporal-documentation', // Usually your repo name.
19-
headTags: [
20-
// JSON-LD structured data so AI agents and search engines can identify
21-
// the product (SoftwareApplication) and disambiguate the brand (sameAs).
22-
{
23-
tagName: 'script',
24-
attributes: {
25-
type: 'application/ld+json',
26-
},
27-
innerHTML: JSON.stringify({
28-
'@context': 'https://schema.org',
29-
'@graph': [
30-
{
31-
'@type': 'Organization',
32-
'@id': 'https://temporal.io/#organization',
33-
name: 'Temporal Technologies',
34-
url: 'https://temporal.io',
35-
logo: 'https://docs.temporal.io/img/favicon.png',
36-
sameAs: [
37-
'https://github.com/temporalio',
38-
'https://x.com/temporalio',
39-
'https://www.youtube.com/c/Temporalio',
40-
],
41-
},
42-
{
43-
'@type': 'SoftwareApplication',
44-
'@id': 'https://temporal.io/#software',
45-
name: 'Temporal',
46-
applicationCategory: 'DeveloperApplication',
47-
operatingSystem: 'Cross-platform',
48-
url: 'https://temporal.io',
49-
downloadUrl: 'https://github.com/temporalio/temporal',
50-
description:
51-
'Temporal is a durable execution platform for building reliable, scalable applications using workflows and activities.',
52-
publisher: { '@id': 'https://temporal.io/#organization' },
53-
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
54-
},
55-
],
56-
}),
57-
},
58-
],
19+
// JSON-LD structured data (Organization/SoftwareApplication/WebPage) is
20+
// rendered per-page instead of injected globally here — see
21+
// src/theme/DocItem/StructuredData and src/constants/organizationSchema.
22+
// A single global block would put the full Organization property set on
23+
// every page, which is exactly the drift risk the JSON-LD audit flagged.
5924
clientModules: ['./src/client/remote-amplitude-analytics.js', './src/client/scrollSidebarToActivePage.ts'],
6025
themeConfig: {
6126
colorMode: {

src/components/CookbookDocItem.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { MDXProvider } from '@mdx-js/react';
1111
import MDXComponents from '@theme/MDXComponents';
1212
import clsx from 'clsx';
1313
import { usePluginData } from '@docusaurus/useGlobalData';
14+
import DocItemStructuredData from '@site/src/theme/DocItem/StructuredData';
1415

1516
import styles from './CookbookDocItem.module.css';
1617

@@ -250,6 +251,7 @@ function InnerCookbookDocItem({ content, tags }: CookbookDocItemProps) {
250251
return (
251252
<HtmlClassNameProvider className="cookbook--centered">
252253
<DocItemMetadata />
254+
<DocItemStructuredData />
253255

254256
<Head>
255257
<title>{title}</title>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Single source of truth for the Organization/SoftwareApplication JSON-LD.
2+
// Per the JSON-LD audit, the same `@id` was showing conflicting `name`,
3+
// `logo`, and `sameAs` values across temporal.io and docs.temporal.io —
4+
// centralizing the canonical object here (instead of hand-authoring it in
5+
// multiple places) is how we keep that from happening again on this
6+
// property. temporal.io and learn.temporal.io maintain their own copies in
7+
// their own codebases and need to be kept byte-identical to this by hand.
8+
9+
export const ORGANIZATION_ID = 'https://temporal.io/#organization';
10+
export const SOFTWARE_APPLICATION_ID = 'https://temporal.io/#software';
11+
12+
// Rendered in full only on the docs landing page (see
13+
// src/theme/DocItem/StructuredData). Every other page should reference it
14+
// via `organizationReference` instead of repeating the full property set.
15+
export const organizationSchema = {
16+
'@type': 'Organization',
17+
'@id': ORGANIZATION_ID,
18+
name: 'Temporal',
19+
alternateName: 'Temporal Technologies',
20+
url: 'https://temporal.io/',
21+
description:
22+
'Temporal is a durable execution platform for building reliable, scalable applications using workflows and activities.',
23+
logo: {
24+
'@type': 'ImageObject',
25+
url: 'https://temporal.io/images/logos/logo-temporal-dark-on-white.png',
26+
width: 512,
27+
height: 512,
28+
},
29+
sameAs: [
30+
'https://www.youtube.com/temporalio',
31+
'https://www.linkedin.com/company/temporal-technologies',
32+
'https://github.com/temporalio',
33+
'https://x.com/temporalio',
34+
],
35+
};
36+
37+
export const softwareApplicationSchema = {
38+
'@type': 'SoftwareApplication',
39+
'@id': SOFTWARE_APPLICATION_ID,
40+
name: 'Temporal',
41+
applicationCategory: 'DeveloperApplication',
42+
operatingSystem: 'Cross-platform',
43+
url: 'https://temporal.io',
44+
downloadUrl: 'https://github.com/temporalio/temporal',
45+
description:
46+
'Temporal is a durable execution platform for building reliable, scalable applications using workflows and activities. This entry describes the open-source server distribution.',
47+
publisher: { '@id': ORGANIZATION_ID },
48+
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
49+
};
50+
51+
// Bare reference for every non-canonical page — attach as `publisher` on
52+
// that page's own schema rather than repeating the full Organization block.
53+
export const organizationReference = {
54+
'@type': 'Organization',
55+
'@id': ORGANIZATION_ID,
56+
};

src/theme/DocItem/Layout/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ import React from 'react';
22
import Layout from '@theme-original/DocItem/Layout';
33
import type LayoutType from '@theme/DocItem/Layout';
44
import type { WrapperProps } from '@docusaurus/types';
5+
import DocItemStructuredData from '../StructuredData';
56

67
type Props = WrapperProps<typeof LayoutType>;
78

89
export default function LayoutWrapper(props: Props): JSX.Element {
910
return (
10-
<Layout {...props} />
11+
<>
12+
<DocItemStructuredData />
13+
<Layout {...props} />
14+
</>
1115
);
1216
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import React from 'react';
2+
import Head from '@docusaurus/Head';
3+
import { useDoc } from '@docusaurus/plugin-content-docs/client';
4+
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
5+
import {
6+
organizationReference,
7+
organizationSchema,
8+
softwareApplicationSchema,
9+
} from '@site/src/constants/organizationSchema';
10+
11+
// The docs landing page is the one canonical page on this property that
12+
// carries the full Organization + SoftwareApplication block (see the
13+
// JSON-LD audit's "Implementation Guidance" on full block placement).
14+
// Duplicating that full block on every page is what caused the drift the
15+
// audit flagged, so every other page gets a lightweight WebPage node with a
16+
// bare `publisher` reference instead.
17+
const CANONICAL_LANDING_PERMALINK = '/';
18+
19+
export default function DocItemStructuredData(): JSX.Element {
20+
const { metadata } = useDoc();
21+
const { siteConfig } = useDocusaurusContext();
22+
23+
if (metadata.permalink === CANONICAL_LANDING_PERMALINK) {
24+
return (
25+
<Head>
26+
<script type="application/ld+json">
27+
{JSON.stringify({
28+
'@context': 'https://schema.org',
29+
'@graph': [organizationSchema, softwareApplicationSchema],
30+
})}
31+
</script>
32+
</Head>
33+
);
34+
}
35+
36+
const pageUrl = `${siteConfig.url}${metadata.permalink}`;
37+
38+
return (
39+
<Head>
40+
<script type="application/ld+json">
41+
{JSON.stringify({
42+
'@context': 'https://schema.org',
43+
'@type': 'WebPage',
44+
'@id': `${pageUrl}#webpage`,
45+
url: pageUrl,
46+
name: metadata.title,
47+
publisher: organizationReference,
48+
})}
49+
</script>
50+
</Head>
51+
);
52+
}

0 commit comments

Comments
 (0)