Skip to content

Commit 6b1a9f0

Browse files
authored
Merge pull request #13591 from bbc/WS-1377-add-speakable-schema-for-select-ws-most-read-pages
[WS-1377]: Add speakable Schema Markup for Select World Service Pages
2 parents 15d53c2 + 8d1a332 commit 6b1a9f0

File tree

2 files changed

+76
-3
lines changed

2 files changed

+76
-3
lines changed

src/app/components/LinkedData/index.test.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,44 @@ describe('LinkedData', () => {
103103
],
104104
};
105105

106+
describe('SpeakableSpecification schema', () => {
107+
const baseProps = {
108+
type: 'WebPage',
109+
seoTitle: 'Hindi Most Read Title',
110+
datePublished: '2024-01-01T12:00:00.000Z',
111+
dateModified: '2024-01-01T13:00:00.000Z',
112+
};
113+
114+
it('includes SpeakableSpecification for Hindi service with title only', () => {
115+
render(
116+
<Context service="hindi">
117+
<LinkedData {...baseProps} />
118+
</Context>,
119+
);
120+
const output = getLinkedDataOutput();
121+
const speakable = output['@graph'].find(
122+
(item: Record<string, unknown>) => item.speakable,
123+
);
124+
expect(speakable).toBeTruthy();
125+
expect(speakable.speakable).toEqual([
126+
{ '@type': 'SpeakableSpecification', xpath: ['/html/head/title'] },
127+
]);
128+
});
129+
130+
it('does not include SpeakableSpecification for non-enabled service', () => {
131+
render(
132+
<Context service="news">
133+
<LinkedData {...baseProps} />
134+
</Context>,
135+
);
136+
const output = getLinkedDataOutput();
137+
const speakable = output['@graph'].find(
138+
(item: Record<string, unknown>) => item.speakable,
139+
);
140+
expect(speakable).toBeUndefined();
141+
});
142+
});
143+
106144
it('should correctly render linked data for Ondemand Radio page', () => {
107145
render(
108146
<Context>

src/app/components/LinkedData/index.tsx

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Helmet } from 'react-helmet';
33
import { RequestContext } from '#contexts/RequestContext';
44
import serialiseForScript from '#lib/utilities/serialiseForScript';
55
import getBrandedImage from '#lib/utilities/getBrandedImage';
6+
import { Services } from '#app/models/types/global';
67
import { ServiceContext } from '../../contexts/ServiceContext';
78
import getAboutTagsContent from './getAboutTagsContent';
89
import { BylineLinkedData, LinkedDataProps } from './types';
@@ -28,6 +29,34 @@ type AuthorStructure = {
2829

2930
type Author = AuthorStructure | AuthorStructure[];
3031

32+
type SpeakableSpecification = {
33+
'@type': 'SpeakableSpecification';
34+
xpath: string[];
35+
};
36+
37+
const SPEAKABLE_ENABLED_SERVICES = ['hindi']; // TODO: to be extended
38+
const SUPPORTED_SPEAKABLE_TYPES = ['WebPage'];
39+
40+
const getSpeakableXpaths = ({
41+
service,
42+
seoTitle,
43+
type,
44+
}: {
45+
service: Services;
46+
seoTitle?: string;
47+
type: string;
48+
}): SpeakableSpecification[] | null => {
49+
if (!SUPPORTED_SPEAKABLE_TYPES.includes(type)) return null;
50+
if (!SPEAKABLE_ENABLED_SERVICES.includes(service)) return null;
51+
if (!seoTitle) return null;
52+
return [
53+
{
54+
'@type': 'SpeakableSpecification',
55+
xpath: ['/html/head/title'],
56+
},
57+
];
58+
};
59+
3160
const LinkedData = ({
3261
showAuthor = false,
3362
type,
@@ -177,6 +206,13 @@ const LinkedData = ({
177206
if (hasByline && bylineAuthors && bylineAuthors.length > 0) {
178207
author = bylineAuthors.length === 1 ? bylineAuthors[0] : bylineAuthors;
179208
}
209+
210+
const speakableXpaths = getSpeakableXpaths({
211+
service,
212+
seoTitle,
213+
type,
214+
});
215+
180216
const linkedData = {
181217
'@type': type,
182218
url: canonicalNonUkLink,
@@ -191,10 +227,9 @@ const LinkedData = ({
191227
coverageEndTime,
192228
inLanguage,
193229
...(aboutTags && { about: getAboutTagsContent(aboutTags) }),
194-
...(showAuthor && {
195-
author,
196-
}),
230+
...(showAuthor && { author }),
197231
...(hasByline && places.length > 0 && { locationCreated }),
232+
...(speakableXpaths && { speakable: speakableXpaths }),
198233
};
199234

200235
return (

0 commit comments

Comments
 (0)