Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(json-ld): add WebSite component #1481

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ package-lock.json
lib
notes.md
.DS_Store
.idea
45 changes: 44 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ If you are using **`pages`** directory then `NextSeo` is **exactly what you need
- [dangerouslySetAllPagesToNoFollow](#dangerouslysetallpagestonofollow)
- [robotsProps](#robotsprops)
- [Twitter](#twitter)
- [facebook](#facebook)
- [Facebook](#facebook)
- [Canonical URL](#canonical-url)
- [Alternate](#alternate)
- [Additional Meta Tags](#additional-meta-tags)
Expand Down Expand Up @@ -111,6 +111,7 @@ If you are using **`pages`** directory then `NextSeo` is **exactly what you need
- [Organization](#organization)
- [Brand](#brand)
- [WebPage](#webpage)
- [WebSite](#website)
- [Image Metadata](#image-metadata)
- [Contributors](#contributors)

Expand Down Expand Up @@ -3474,6 +3475,48 @@ export default () => (

For reference and more info check [Docs](https://schema.org/WebPage)

### WebSite

```jsx
import React from 'react';
import { WebSiteJsonLd } from 'next-seo';

export default () => (
<>
<h1>WebSite</h1>
<WebSiteJsonLd
name="Example"
alternateName={['Example Org', 'Example Organization']}
url="https://example.org"
publisher={{
id: 'https://example.org/#organization',
}}
/>
</>
);
```

**Data required properties**

| Property | Info |
| -------- | --------------- |
| `name` | 'The site name' |

**Data Recommended properties**

| Property | Info |
| --------------- | -------------------------------------------------------- |
| `url` | The URL of the website |
| `alternateName` | One or multiple alternate names for the site |
| `publisher` | |
| `publisher.id` | Id of the Person or Organization that published the site |

**Other**
| `useAppDir` | This should be set to true if using the new app directory. Not required if outside of the app
directory. |

For reference and more info check [Docs](https://schema.org/WebSite)

### Image Metadata

```jsx
Expand Down
57 changes: 57 additions & 0 deletions cypress/e2e/webSiteJsonLd.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { assertSchema } from '@cypress/schema-tools';
import schemas from '../schemas';

describe('WebPage JSON-LD', () => {
it('matches schema', () => {
cy.visit('http://localhost:3000/jsonld/webSite');
cy.get('head script[type="application/ld+json"]').then(tags => {
const jsonLD = JSON.parse(tags[0].innerHTML);
assertSchema(schemas)('WebSite', '1.0.0')(jsonLD);
});
});

it('renders with all props', () => {
cy.visit('http://localhost:3000/jsonld/webSite');
cy.get('head script[type="application/ld+json"]').then(tags => {
const jsonLD = JSON.parse(tags[0].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'Example',
alternateName: ['Example Org', 'Example Organization'],
url: 'https://example.org',
publisher: {
'@id': 'https://example.org/#organization',
},
});
});
});

it('renders without a publisher', () => {
cy.visit('http://localhost:3000/jsonld/webSite/withoutPublisher');
cy.get('head script[type="application/ld+json"]').then(tags => {
const jsonLD = JSON.parse(tags[0].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'Example',
alternateName: ['Example Org', 'Example Organization'],
url: 'https://example.org',
});
});
});

it('renders with a single alternate name', () => {
cy.visit('http://localhost:3000/jsonld/webSite/withSingleAlternateName');
cy.get('head script[type="application/ld+json"]').then(tags => {
const jsonLD = JSON.parse(tags[0].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'Example',
alternateName: 'Example Organization',
url: 'https://example.org',
});
});
});
});
3 changes: 2 additions & 1 deletion cypress/schemas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import howToVersions from './how-to-schema';
import imageVersions from './image-schema';
import campgroundVersions from './campground-schema';
import parkVersions from './park-schema';

import webSiteVersions from './web-site-schema';

const schemas = combineSchemas(
articleVersions,
Expand Down Expand Up @@ -61,5 +61,6 @@ const schemas = combineSchemas(
imageVersions,
campgroundVersions,
parkVersions,
webSiteVersions,
);
export default schemas;
61 changes: 61 additions & 0 deletions cypress/schemas/web-site-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { versionSchemas } from '@cypress/schema-tools';

const webSite100 = {
version: {
major: 1,
minor: 0,
patch: 0,
},
schema: {
type: 'object',
title: 'WebSite',
description: 'An example schema describing JSON-LD for type: WebSite',
properties: {
'@context': {
type: 'string',
description: 'Schema.org context',
},
'@type': {
type: 'string',
description: 'JSON-LD type: WebSite',
},
name: {
type: 'string',
description: 'The site name',
},
url: {
type: 'string',
description: 'The URL of the website',
},
alternateName: {
type: 'array',
items: {
type: 'string',
},
description: 'One or multiple alternate names for the site',
},
publisher: {
type: 'object',
properties: {
'@id': {
type: 'string',
description: 'Id of the publisher node',
},
},
},
},
},
example: {
'@context': 'https://schema.org',
'@type': 'WebSite',
url: 'https://example.org',
name: 'Example',
alternateName: ['Example Org', 'Example Organization'],
publisher: {
'@id': 'https://example.org/#organization',
},
},
};

const webSiteVersions = versionSchemas(webSite100);
export default webSiteVersions;
1 change: 1 addition & 0 deletions e2e/pages/jsonld/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const allJsonLDPages = [
'videoGame',
'webPage',
'webPage2',
'webSite',
];

const Home = () => (
Expand Down
20 changes: 20 additions & 0 deletions e2e/pages/jsonld/webSite/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import { WebSiteJsonLd } from '../../../..';

function WebPage() {
return (
<>
<h1>WebSite</h1>
<WebSiteJsonLd
name="Example"
alternateName={['Example Org', 'Example Organization']}
url="https://example.org"
publisher={{
id: 'https://example.org/#organization',
}}
/>
</>
);
}

export default WebPage;
17 changes: 17 additions & 0 deletions e2e/pages/jsonld/webSite/withSingleAlternateName.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { WebSiteJsonLd } from '../../../..';

function WebPage() {
return (
<>
<h1>WebSite</h1>
<WebSiteJsonLd
name="Example"
alternateName="Example Organization"
url="https://example.org"
/>
</>
);
}

export default WebPage;
17 changes: 17 additions & 0 deletions e2e/pages/jsonld/webSite/withoutPublisher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { WebSiteJsonLd } from '../../../..';

function WebPage() {
return (
<>
<h1>WebSite</h1>
<WebSiteJsonLd
name="Example"
alternateName={['Example Org', 'Example Organization']}
url="https://example.org"
/>
</>
);
}

export default WebPage;
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,5 @@ export {
CampgroundJsonLdProps,
} from './jsonld/campground';
export { default as ParkJsonLd, ParkJsonLdProps } from './jsonld/park';
export { default as WebSiteJsonLd, WebSiteJsonLdProps } from './jsonld/webSite';
export { DefaultSeoProps, NextSeoProps } from './types';
35 changes: 35 additions & 0 deletions src/jsonld/webSite.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';

import { JsonLd, JsonLdProps } from './jsonld';
import { WebSitePublisher } from '../types';
import { setWebSitePublisher } from '../utils/schema/setWebSitePublisher';

export interface WebSiteJsonLdProps extends JsonLdProps {
name: string;
url?: string;
alternateName?: string | string[];
publisher?: WebSitePublisher;
}

function WebSiteJsonLd({
type = 'WebSite',
keyOverride,
publisher,
...rest
}: WebSiteJsonLdProps) {
const data = {
...rest,
publisher: setWebSitePublisher(publisher),
};

return (
<JsonLd
type={type}
keyOverride={keyOverride}
{...data}
scriptKey="WebSite"
/>
);
}

export default WebSiteJsonLd;
12 changes: 12 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export type StepDetails = {
export interface Person {
name: string;
}

export interface Answer {
text: string;
dateCreated?: string;
Expand All @@ -79,10 +80,12 @@ export interface Instruction {
url?: string;
image?: string;
}

export interface Performer {
type?: 'Person' | 'PerformingGroup';
name: string;
}

export interface Place {
name: string;
address: Address;
Expand Down Expand Up @@ -123,6 +126,7 @@ export interface ContactPoint {
availableLanguage?: string | string[];
contactOption?: string | string[];
}

export interface CreativeWork {
author: string;
about: string;
Expand All @@ -143,16 +147,19 @@ export interface Question {
questionName: string;
acceptedAnswerText: string;
}

export interface Provider {
type?: 'Organization' | 'Person';
name: string;
url?: string;
}

export interface ItemListElements {
item: string;
name: string;
position: number;
}

export interface OpenGraphMedia {
url: string;
width?: number | null;
Expand Down Expand Up @@ -395,6 +402,10 @@ export type Publisher = {
name: string;
};

export type WebSitePublisher = {
id: string;
};

export type ReviewedBy = {
type?: string;
name: string;
Expand Down Expand Up @@ -511,4 +522,5 @@ export interface DefaultSeoProps {
additionalLinkTags?: ReadonlyArray<LinkTag>;
children?: never;
}

export interface BuildTagsParams extends DefaultSeoProps, NextSeoProps {}
11 changes: 11 additions & 0 deletions src/utils/schema/setWebSitePublisher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { WebSitePublisher } from '../../types';

export function setWebSitePublisher(publisher?: WebSitePublisher) {
if (publisher) {
return {
'@id': publisher.id,
};
}

return undefined;
}
Loading