Skip to content

Commit

Permalink
Add support for Corporate Contact JSON-LD (garmeeh#40)
Browse files Browse the repository at this point in the history
Include support to [corporate contact](https://developers.google.com/search/docs/data-types/corporate-contact) and corresponding tests and documentation
  • Loading branch information
erickeno authored and garmeeh committed Feb 17, 2019
1 parent 51014cf commit 8ee303a
Show file tree
Hide file tree
Showing 7 changed files with 311 additions and 1 deletion.
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ Below you will find a very basic page implementing each of the available JSON-LD
- [Breadcrumb](#breadcrumb)
- [Blog](#blog)
- [Course](#course)
- [Corporate Contact](#corporate-contact)
- [Local Business](#local-business)
- [Product](#product)
- [Social Profile](#social-profile)
Expand Down Expand Up @@ -699,6 +700,61 @@ export default () => (
);
```

### Corporate Contact

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

export default () => (
<>
<h1>Corporate Contact JSON-LD</h1>
<CorporateContactJsonLd
url="http://www.your-company-site.com"
logo="http://www.example.com/logo.png"
contactPoint={[
{
telephone: '+1-401-555-1212',
contactType: 'customer service',
areaServed: 'US',
availableLanguage: ['English', 'Spanish', 'French'],
},
{
telephone: '+1-877-746-0909',
contactType: 'customer service',
contactOption: 'TollFree',
availableLanguage: 'English',
},
{
telephone: '+1-877-453-1304',
contactType: 'technical support',
contactOption: 'TollFree',
areaServed: ['US', 'CA'],
availableLanguage: ['English', 'French'],
},
]}
/>
</>
);
```

**Required properties**

| Property | Info |
| -------------------------- | ----------------------------------------------------------------------------------------------- |
| `url` | Url to the home page of the company's official site. |
| `contactPoint` | |
| `contactPoint.telephone` | An internationalized version of the phone number, starting with the "+" symbol and country code |
| `contactPoint.contactType` | Description of the purpose of the phone number i.e. `Technical Support`. |

**Recommended ContactPoint properties**

| Property | Info |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `contactPoint.areaServed` | `String` or `Array` of geographical regions served by the business. Example `"US"` or `["US", "CA", "MX"]` |
| `contactPoint.availableLanguage` | Details about the language spoken. Example `"English"` or `["English", "French"]` |
| `gecontactPointo.contactOption` | Details about the phone number. Example `"TollFree"` |

### Local Business

Local business is supported with a sub-set of properties.
Expand Down
52 changes: 51 additions & 1 deletion e2e/cypress/e2e/jsonld.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assertSchema } from '@cypress/schema-tools';
import schemas from '../schemas';

const expectedJSONResults = 8;
const expectedJSONResults = 9;

const articleLdJsonIndex = 0;
const breadcrumbLdJsonIndex = 1;
Expand All @@ -11,6 +11,7 @@ const localBusinessLdJsonIndex = 4;
const logoLdJsonIndex = 5;
const productLdJsonIndex = 6;
const socialProfileLdJsonIndex = 7;
const corporateContactIndex = 8;

describe('Validates JSON-LD For:', () => {
it('Article', () => {
Expand Down Expand Up @@ -351,4 +352,53 @@ describe('Validates JSON-LD For:', () => {
});
});
});

it('CorporateContact', () => {
cy.visit('http://localhost:3000/jsonld');
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[corporateContactIndex].innerHTML);
assertSchema(schemas)('Corporate Contact', '1.0.0')(jsonLD);
});
});

it('Corporate Contact Matches', () => {
cy.visit('http://localhost:3000/jsonld');
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[corporateContactIndex].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'https://schema.org',
'@type': 'Organization',
url: 'http://www.your-company-site.com',
logo: 'http://www.example.com/logo.png',
contactPoint: [
{
'@type': 'ContactPoint',
telephone: '+1-401-555-1212',
contactType: 'customer service',
areaServed: 'US',
availableLanguage: ['English', 'Spanish', 'French'],
},
{
'@type': 'ContactPoint',
telephone: '+1-877-746-0909',
contactType: 'customer service',
contactOption: 'TollFree',
availableLanguage: 'English',
},
{
'@type': 'ContactPoint',
telephone: '+1-877-453-1304',
contactType: 'technical support',
contactOption: 'TollFree',
areaServed: ['US', 'CA'],
availableLanguage: ['English', 'French'],
},
],
});
});
});
});
100 changes: 100 additions & 0 deletions e2e/cypress/schemas/corporate-contact-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { versionSchemas } from '@cypress/schema-tools';

const contactPoint100 = {
version: {
major: 1,
minor: 0,
patch: 0,
},
schema: {
type: 'object',
description: 'Corporate Contact - ContactPoint',
properties: {
'@type': {
type: 'string',
description: 'ContactPoint',
},
telephone: {
type: 'string',
description: 'Telephone number of the company',
},
contactType: {
type: 'string',
description: 'The main usage of the phone number',
},
areaServed: {
type: ['string', 'array'],
description: 'Geographical region served',
},
availableLanguage: {
type: ['string', 'array'],
description: 'Language spoken',
},
contactOption: {
type: 'string',
description: 'Details about the number',
},
},
required: ['@type', 'telephone', 'contactType'],
additionalProperties: false,
},
example: {
'@type': 'ContactPoint',
contactType: 'customer service',
telephone: '+1-877-746-0909',
areaServed: 'US',
availableLanguage: ['English', 'Spanish', 'French'],
contactOption: 'TollFree',
},
};

const corporateContact100 = {
version: {
major: 1,
minor: 0,
patch: 0,
},
schema: {
type: 'object',
title: 'Corporate Contact',
description:
'An example schema describing JSON-LD for type: Corporate Contact',
properties: {
'@context': {
type: 'string',
description: 'Schema.org context',
},
'@type': {
type: 'string',
description: 'Organization',
},
url: {
type: 'string',
description: 'The URL of the website associated with the logo.',
},
logo: {
type: 'string',
description: 'The url for the company logo',
},
contactPoint: {
type: 'array',
items: {
...contactPoint100.schema,
},
see: contactPoint100,
},
},
required: ['@context', '@type', 'url', 'contactPoint'],
additionalProperties: false,
},
example: {
'@context': 'https://schema.org',
'@type': 'Organization',
url: 'http://www.your-company-site.com',
logo: 'http://www.example.com/logo.png',
contactPoint: [contactPoint100.example],
},
};

const corporateContact = versionSchemas(corporateContact100);
export default corporateContact;
2 changes: 2 additions & 0 deletions e2e/cypress/schemas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import localBusiness from './local-business-schema';
import logoVersions from './logo-schema';
import productVersions from './product-schema';
import socialProfileVersions from './social-profile-schema';
import corporateContactVersions from './corporate-contact-schema';

const schemas = combineSchemas(
articleVersions,
Expand All @@ -18,5 +19,6 @@ const schemas = combineSchemas(
logoVersions,
productVersions,
socialProfileVersions,
corporateContactVersions,
);
export default schemas;
26 changes: 26 additions & 0 deletions e2e/pages/jsonld.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
LogoJsonLd,
ProductJsonLd,
SocialProfileJsonLd,
CorporateContactJsonLd,
} from '../../dist';
import Links from '../components/links';

Expand Down Expand Up @@ -157,6 +158,31 @@ export default () => (
'http://plus.google.com/your_profile',
]}
/>
<CorporateContactJsonLd
url="http://www.your-company-site.com"
logo="http://www.example.com/logo.png"
contactPoint={[
{
telephone: '+1-401-555-1212',
contactType: 'customer service',
areaServed: 'US',
availableLanguage: ['English', 'Spanish', 'French'],
},
{
telephone: '+1-877-746-0909',
contactType: 'customer service',
contactOption: 'TollFree',
availableLanguage: 'English',
},
{
telephone: '+1-877-453-1304',
contactType: 'technical support',
contactOption: 'TollFree',
areaServed: ['US', 'CA'],
availableLanguage: ['English', 'French'],
},
]}
/>
<Links />
</>
);
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import LocalBusinessJsonLd from './jsonld/localBusiness';
import LogoJsonLd from './jsonld/logo';
import ProductJsonLd from './jsonld/product';
import SocialProfileJsonLd from './jsonld/socialProfile';
import CorporateContactJsonLd from './jsonld/corporateContact';

export default DefaultSeo;
export {
Expand All @@ -18,4 +19,5 @@ export {
LogoJsonLd,
ProductJsonLd,
SocialProfileJsonLd,
CorporateContactJsonLd,
};
74 changes: 74 additions & 0 deletions src/jsonld/corporateContact.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from 'react';
import PropTypes from 'prop-types';
import Head from 'next/head';

import markup from '../utils/markup';

const formatIfArray = value =>
Array.isArray(value) ? `[${value.map(val => `"${val}"`)}]` : `"${value}"`;

const buildContactPoint = contactPoint =>
contactPoint.map(
contact => `{
"@type": "ContactPoint",
"telephone": "${contact.telephone}",
"contactType": "${contact.contactType}"${
contact.areaServed
? `,
"areaServed": ${formatIfArray(contact.areaServed)}`
: ''
}${
contact.availableLanguage
? `,
"availableLanguage": ${formatIfArray(contact.availableLanguage)}`
: ''
}${
contact.contactOption
? `,
"contactOption": "${contact.contactOption}"`
: ''
}
}`,
);
const CorporateContactJsonLd = ({ url, logo, contactPoint = [] }) => {
const jslonld = `{
"@context": "https://schema.org",
"@type": "Organization",
"url": "${url}",
${logo ? `"logo": "${logo}",` : ''}
"contactPoint": [${buildContactPoint(contactPoint)}]
}`;

return (
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={markup(jslonld)}
key="jsonld-corporate-contact"
/>
</Head>
);
};

CorporateContactJsonLd.defaultProps = {
logo: null,
};

CorporateContactJsonLd.propTypes = {
logo: PropTypes.string,
url: PropTypes.string.isRequired,
contactPoint: PropTypes.arrayOf(
PropTypes.shape({
telephone: PropTypes.string.isRequired,
contactType: PropTypes.string.isRequired,
areaServed: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
availableLanguage: PropTypes.oneOfType([
PropTypes.string,
PropTypes.array,
]),
contactOption: PropTypes.string,
}),
).isRequired,
};

export default CorporateContactJsonLd;

0 comments on commit 8ee303a

Please sign in to comment.