Skip to content

Commit

Permalink
Add support for video sitemaps
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike Wheeler committed Nov 16, 2023
1 parent 374830d commit 4f3704c
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 1 deletion.
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ These parameters mean:
* @property {Object} [alternates] alternative versions of this link (useful for multi-language)
* @property {Array} [alternates.languages] list of languages that are enabled
* @property {Array} [images] list of images links related to the hit
* @property {Array} [videos] list of videos links related to the hit
* @property {function} [alternates.hitToURL] function to transform a language into a url of this object
*/
```
Expand Down Expand Up @@ -138,6 +139,60 @@ function hitToParams({

For more information, see https://support.google.com/webmasters/answer/178636?hl=en

### Video Sitemaps

If you want your sitemap to include [Google video extensions](https://developers.google.com/search/docs/crawling-indexing/sitemaps/video-sitemaps), return an array for each hit containing objects with the following keys:

```js
/**
* @typedef {Object} Video
* @property {string} [title] Video title
* @property {string} [description] Video description
* @property {string} [thumbnail_loc] location of video thumbnail image
* @property {string} [content_loc] location of video file
* @property {string} [player_loc] location of video player
*/
```

For example:

```js
function hitToParams({
objectID,
modified,
downloadsRatio,
videoFile,
videoThumbnail,
videoDescription
name,
}) {
const url = ({ lang, objectID }) =>
`https://${lang}.yoursite.com/${lang}/detail/${objectID}`;
const loc = url({ lang: 'en', objectID });
const lastmod = new Date().toISOString();
const priority = Math.random();
return {
loc,
lastmod,
priority,
videos: [
{
title: name,
description: videoDescription,
thumbnail_loc: videoThumbnail,
content_loc: videoFile
},
],
alternates: {
languages: ['fr', 'pt-BR', 'zh-Hans'],
hitToURL: lang => url({ lang, objectID }),
},
};
}
```

For more information, see https://developers.google.com/search/docs/crawling-indexing/sitemaps/video-sitemaps

## Custom queries

You can pass a `params` parameter to `algoliaSitemap`. This allows you to narrow down the returned results. For instance, in order to have `hitToParams` called for every products in the `phone` category, we could do:
Expand Down
68 changes: 67 additions & 1 deletion sitemap.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const isValidURL = ({
priority,
alternates,
images,
videos,
}) => {
// loc
// eslint-disable-next-line camelcase
Expand Down Expand Up @@ -118,6 +119,46 @@ see https://support.google.com/webmasters/answer/178636?hl=en for more informati
});
}

// videos
const _videosError = `videos ${JSON.stringify(videos)} was not valid. An array with video locations like
[{
thumbnail_loc: 'https://example.com/test/my-video.jpg',
title: 'Video title',
description: 'Video description',
content_loc: 'https://example.com/test/my-video.mp4'
}]
was expected.
see https://support.google.com/webmasters/answer/178636?hl=en for more information.`;

if (videos !== undefined) {
if (!(videos instanceof Array)) {
throw new Error(_videosError);
}
videos.forEach(vid => {
if (typeof vid.thumbnail_loc !== 'string') {
throw new Error(_videosError);
}
if (!isURL(vid.thumbnail_loc)) {
throw new Error(_videosError);
}
if (typeof vid.title !== 'string') {
throw new Error(_videosError);
}
if (typeof vid.description !== 'string') {
throw new Error(_videosError);
}
if (typeof vid.content_loc !== 'string' && typeof vid.player_loc !== 'string') {
throw new Error(_videosError);
}
if (!isURL(vid.content_loc) && !isURL(vid.player_loc)) {
throw new Error(_videosError);
}
});
}

// alternates
const _alternatesError = `alternates ${JSON.stringify(
alternates
Expand Down Expand Up @@ -151,6 +192,7 @@ was expected.`;
priority: priority === undefined ? undefined : priority.toFixed(1),
alternates,
images,
videos,
};
};

Expand All @@ -173,6 +215,17 @@ function createSitemap(entries = []) {
{img.license && <imagelicense>{img.license}</imagelicense>}
</imageimage>
);

const _videos = vid => (
<videovideo>
<videotitle>{vid.title}</videotitle>
<videodescription>{vid.description}</videodescription>
<videothumbnailLoc>{vid.thumbnail_loc}</videothumbnailLoc>
{vid.content_loc && <videocontentLoc>{vid.content_loc}</videocontentLoc>}
{vid.player_loc && <videoplayerLoc>{vid.player_loc}</videoplayerLoc>}
</videovideo>
);

const url = args => {
const {
loc = undefined,
Expand All @@ -181,6 +234,7 @@ function createSitemap(entries = []) {
priority = undefined,
alternates = undefined,
images = undefined,
videos = undefined,
} = isValidURL(args);

return (
Expand All @@ -193,6 +247,7 @@ function createSitemap(entries = []) {
{priority && <priority>{priority}</priority>}
{alternates && _alternates(alternates)}
{images && images.length > 0 ? images.map(_images) : null}
{videos && videos.length > 0 ? videos.map(_videos) : null}
</url>
);
};
Expand All @@ -203,6 +258,7 @@ function createSitemap(entries = []) {
<urlset
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns_image="http://www.google.com/schemas/sitemap-image/1.1"
xmlns_video="http://www.google.com/schemas/sitemap-video/1.1"
>
{entries.map(url)}
</urlset>
Expand All @@ -222,8 +278,18 @@ function createSitemap(entries = []) {
.replace(/<\/imagetitle>/g, ']]></imagetitle>')
.replace(/<imagecaption>/g, '<imagecaption><![CDATA[')
.replace(/<\/imagecaption>/g, ']]></imagecaption>')
.replace(/<videotitle>/g, '<videotitle><![CDATA[')
.replace(/<\/videotitle>/g, ']]></videotitle>')
.replace(/<videodescription>/g, '<videodescription><![CDATA[')
.replace(/<\/videodescription>/g, ']]></videodescription>')
// <imageimage></imageimage> ➡️ <image:image></image:image>
.replace(/<\/?image/g, '$&:'),
.replace(/<\/?image/g, '$&:')
// <videovideo></videovideo> ➡️ <video:video></video:video>
.replace(/<\/?video/g, '$&:')
// Video sitemaps use underscores in attribute names
.replace(/<(\/?)video:thumbnailLoc/g, '<$1video:thumbnail_loc')
.replace(/<(\/?)video:contentLoc/g, '<$1video:content_loc')
.replace(/<(\/?)video:playerLoc/g, '<$1video:player_loc')
};
}

Expand Down

0 comments on commit 4f3704c

Please sign in to comment.