Repository: garmeeh/next-seo
Pull request #119 (2019-11-13 21:46:10)

docs: add nik-john as a contributor
Adds @nik-john as a contributor for doc, code, test.

This was requested by garmeeh [in this comment](https://github.com/garmeeh/next-seo/pull/117#issuecomment-553618454)


Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 615f345..a50fa61 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -140,6 +140,17 @@
         "code",
         "test"
       ]
+    },
+    {
+      "login": "nik-john",
+      "name": "nikjohn",
+      "avatar_url": "https://avatars2.githubusercontent.com/u/1117182?v=4",
+      "profile": "https://github.com/nik-john",
+      "contributions": [
+        "doc",
+        "code",
+        "test"
+      ]
     }
   ],
   "contributorsPerLine": 7
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 82cfb99..bea1682 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,3 @@
 {
-  "cSpell.words": ["noindex"]
+  "cSpell.words": ["noindex", "nofollow"]
 }
diff --git a/README.md b/README.md
index e16fcc9..04e9c6f 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Next SEO
 
-[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors)
+[![All Contributors](https://img.shields.io/badge/all_contributors-14-orange.svg?style=flat-square)](#contributors)
 
 Next SEO is a plugin that makes managing your SEO easier in Next.js projects.
 
@@ -24,6 +24,8 @@ Version One docs can be found [here](https://github.com/garmeeh/next-seo/tree/su
     - [Title Template](#title-template)
     - [No Index](#no-index)
     - [dangerouslySetAllPagesToNoIndex](#dangerouslysetallpagestonoindex)
+    - [No Follow](#no-follow)
+    - [dangerouslySetAllPagesToNoFollow](#dangerouslysetallpagestonofollow)
     - [Twitter](#twitter)
     - [facebook](#facebook)
     - [Canonical URL](#canonical-url)
@@ -235,6 +237,7 @@ From now on all of your pages will have the defaults above applied.
 | `titleTemplate`                    | string                  | Allows you to set default title template that will be added to your title [More Info](#title-template)                                                                               |
 | `title`                            | string                  | Set the meta title of the page                                                                                                                                                       |
 | `noindex`                          | boolean (default false) | Sets whether page should be indexed or not [More Info](#no-index)                                                                                                                    |
+| `nofollow`                         | boolean (default false) | Sets whether page should be followed or not [More Info](#no-follow)                                                                                                                  |
 | `description`                      | string                  | Set the page meta description                                                                                                                                                        |
 | `canonical`                        | string                  | Set the page canonical url                                                                                                                                                           |
 | `mobileAlternate.media`            | string                  | Set what screen size the mobile website should be served from                                                                                                                        |
@@ -286,9 +289,9 @@ titleTemplate = '%s | Next SEO';
 
 #### No Index
 
-Setting this to `true` will set `no-index`, `no-follow`. This works on a page by page basis.
+Setting this to `true` will set `noindex,follow` (to set `nofollow`, please refer to [`nofollow`](#noFollow)). This works on a page by page basis. This property works in tandem with the `nofollow` property and together they populate the `robots` and `googlebot` meta tags.
 
-So this property is a little different than all the others in the sense that setting it as a default does not work as expected. This is due to the fact Next SEO already has a default of `index` as it is an SEO plugin after all. So if you want to globally set `noindex` please see [dangerouslySetAllPagesToNoIndex](#dangerouslySetAllPagesToNoIndex)
+**Note:** The `noindex` and the [`nofollow`](#noFollow) properties are a little different than all the others in the sense that setting them as a default does not work as expected. This is due to the fact Next SEO already has a default of `index,follow` because `next-seo` is a SEO plugin after all. So if you want to globally these properties, please see [dangerouslySetAllPagesToNoIndex](#dangerouslySetAllPagesToNoIndex) and [dangerouslySetAllPagesToNoFollow](#dangerouslySetAllPagesToNoFollow).
 
 **Example No Index on a single page:**
 
@@ -304,6 +307,11 @@ export default () => (
     <p>This page is no indexed</p>
   </>
 );
+
+/* 
+<meta name="robots" content="noindex,follow">
+<meta name="googlebot" content="noindex,follow">
+*/
 ```
 
 #### dangerouslySetAllPagesToNoIndex
@@ -312,6 +320,49 @@ It has the prefix of `dangerously` because it will `noindex` all pages. As this
 
 The only way to unset this, is by removing the prop from the `DefaultSeo` in your custom `<App>`.
 
+#### No Follow
+
+Setting this to `true` will set `index,nofollow` (to set `noindex`, please refer to [`noindex`](#noIndex)). This works on a page by page basis. This property works in tandem with the `noindex` property and together they populate the `robots` and `googlebot` meta tags.
+
+**Note:** The `noindex` and the [`nofollow`](#noFollow) properties are a little different than all the others in the sense that setting them as a default does not work as expected. This is due to the fact Next SEO already has a default of `index,follow` because `next-seo` is a SEO plugin after all. So if you want to globally these properties, please see [dangerouslySetAllPagesToNoIndex](#dangerouslySetAllPagesToNoIndex) and [dangerouslySetAllPagesToNoFollow](#dangerouslySetAllPagesToNoFollow).
+
+**Example No Follow on a single page:**
+
+If you have a single page that you want no indexed you can achieve this by:
+
+```jsx
+import React from 'react';
+import NextSeo from 'next-seo';
+
+export default () => (
+  <>
+    <NextSeo nofollow={true} />
+    <p>This page is not followed</p>
+  </>
+);
+
+/* 
+<meta name="robots" content="index,nofollow">
+<meta name="googlebot" content="index,nofollow">
+*/
+```
+
+#### dangerouslySetAllPagesToNoFollow
+
+It has the prefix of `dangerously` because it will `nofollow` all pages. As this is an SEO plugin, that is kinda dangerous action. It is **not** bad to use this, just please be sure you want to `nofollow` **EVERY** page. You can still override this at a page level if you have a use case to `follow` a page. This can be done by setting `nofollow: false`.
+
+The only way to unset this, is by removing the prop from the `DefaultSeo` in your custom `<App>`.
+
+| `noindex` | `nofollow` | `meta` content of `robots`, `googlebot` |
+| --------- | ---------- | --------------------------------------- |
+| --        | --         | `index,follow` (default)                |
+| false     | false      | `index,follow`                          |
+| true      | --         | `noindex,follow`                        |
+| true      | false      | `noindex,follow`                        |
+| --        | true       | `index,nofollow`                        |
+| false     | true       | `index,nofollow`                        |
+| true      | true       | `noindex,nofollow`                      |
+
 #### Twitter
 
 Twitter will read the `og:title`, `og:image` and `og:description` tags for their card, this is why `next-seo` omits `twitter:title`, `twitter:image` and `twitter:description` so not to duplicate.
@@ -1177,6 +1228,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
     <td align="center"><a href="https://github.com/duckranger"><img src="https://avatars0.githubusercontent.com/u/2087890?v=4" width="100px;" alt="Nimo Naamani"/><br /><sub><b>Nimo Naamani</b></sub></a><br /><a href="https://github.com/garmeeh/next-seo/commits?author=duckranger" title="Documentation">📖</a></td>
     <td align="center"><a href="https://github.com/calvinvoo2"><img src="https://avatars2.githubusercontent.com/u/12223423?v=4" width="100px;" alt="Calvin Ng Tjioe"/><br /><sub><b>Calvin Ng Tjioe</b></sub></a><br /><a href="https://github.com/garmeeh/next-seo/commits?author=calvinvoo2" title="Code">💻</a></td>
     <td align="center"><a href="https://github.com/petertulala"><img src="https://avatars1.githubusercontent.com/u/613623?v=4" width="100px;" alt="Peter Tulala"/><br /><sub><b>Peter Tulala</b></sub></a><br /><a href="https://github.com/garmeeh/next-seo/commits?author=petertulala" title="Code">💻</a> <a href="https://github.com/garmeeh/next-seo/commits?author=petertulala" title="Tests">⚠️</a></td>
+    <td align="center"><a href="https://github.com/nik-john"><img src="https://avatars2.githubusercontent.com/u/1117182?v=4" width="100px;" alt="nikjohn"/><br /><sub><b>nikjohn</b></sub></a><br /><a href="https://github.com/garmeeh/next-seo/commits?author=nik-john" title="Documentation">📖</a> <a href="https://github.com/garmeeh/next-seo/commits?author=nik-john" title="Code">💻</a> <a href="https://github.com/garmeeh/next-seo/commits?author=nik-john" title="Tests">⚠️</a></td>
   </tr>
 </table>
 
diff --git a/src/meta/buildTags.tsx b/src/meta/buildTags.tsx
index 591695d..6a00eb4 100644
--- a/src/meta/buildTags.tsx
+++ b/src/meta/buildTags.tsx
@@ -4,6 +4,7 @@ import { BuildTagsParams } from '../types';
 const defaults = {
   templateTitle: '',
   noindex: false,
+  nofollow: false,
   defaultOpenGraphImageWidth: 0,
   defaultOpenGraphImageHeight: 0,
   defaultOpenGraphVideoWidth: 0,
@@ -26,26 +27,40 @@ const buildTags = (config: BuildTagsParams) => {
     tagsToRender.push(<title key="title">{updatedTitle}</title>);
   }
 
-  if (config.noindex === false) {
-    tagsToRender.push(
-      <meta key="robots" name="robots" content="index,follow" />,
-    );
-    tagsToRender.push(
-      <meta key="googlebot" name="googlebot" content="index,follow" />,
-    );
-  } else if (
+  const noindex =
     config.noindex ||
     defaults.noindex ||
-    config.dangerouslySetAllPagesToNoIndex
-  ) {
+    config.dangerouslySetAllPagesToNoIndex;
+  const nofollow =
+    config.nofollow ||
+    defaults.nofollow ||
+    config.dangerouslySetAllPagesToNoFollow;
+
+  if (noindex || nofollow) {
     if (config.dangerouslySetAllPagesToNoIndex) {
       defaults.noindex = true;
     }
+    if (config.dangerouslySetAllPagesToNoFollow) {
+      defaults.nofollow = true;
+    }
+
     tagsToRender.push(
-      <meta key="robots" name="robots" content="noindex,nofollow" />,
+      <meta
+        key="robots"
+        name="robots"
+        content={`${noindex ? 'noindex' : 'index'},${
+          nofollow ? 'nofollow' : 'follow'
+        }`}
+      />,
     );
     tagsToRender.push(
-      <meta key="googlebot" name="googlebot" content="noindex,nofollow" />,
+      <meta
+        key="googlebot"
+        name="googlebot"
+        content={`${noindex ? 'noindex' : 'index'},${
+          nofollow ? 'nofollow' : 'follow'
+        }`}
+      />,
     );
   } else {
     tagsToRender.push(
diff --git a/src/meta/defaultSEO.tsx b/src/meta/defaultSEO.tsx
index 68d7992..58b09c4 100644
--- a/src/meta/defaultSEO.tsx
+++ b/src/meta/defaultSEO.tsx
@@ -10,6 +10,7 @@ export default class extends Component<DefaultSeoProps, {}> {
       title,
       titleTemplate,
       dangerouslySetAllPagesToNoIndex = false,
+      dangerouslySetAllPagesToNoFollow = false,
       description,
       canonical,
       facebook,
@@ -30,6 +31,7 @@ export default class extends Component<DefaultSeoProps, {}> {
           title,
           titleTemplate,
           dangerouslySetAllPagesToNoIndex,
+          dangerouslySetAllPagesToNoFollow,
           description,
           canonical,
           facebook,
diff --git a/src/meta/nextSEO.tsx b/src/meta/nextSEO.tsx
index ee5a4e1..6908715 100644
--- a/src/meta/nextSEO.tsx
+++ b/src/meta/nextSEO.tsx
@@ -8,6 +8,7 @@ export default class extends Component<NextSeoProps, {}> {
     const {
       title,
       noindex = false,
+      nofollow,
       description,
       canonical,
       openGraph,
@@ -24,6 +25,7 @@ export default class extends Component<NextSeoProps, {}> {
         {buildTags({
           title,
           noindex,
+          nofollow,
           description,
           canonical,
           facebook,
diff --git a/src/types.ts b/src/types.ts
index 5dd57b2..3cb8feb 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -104,6 +104,7 @@ export interface NextSeoProps {
   title?: string;
   titleTemplate?: string;
   noindex?: boolean;
+  nofollow?: boolean;
   description?: string;
   canonical?: string;
   mobileAlternate?: MobileAlternate;
@@ -116,10 +117,10 @@ export interface NextSeoProps {
 
 export interface DefaultSeoProps extends NextSeoProps {
   dangerouslySetAllPagesToNoIndex?: boolean;
+  dangerouslySetAllPagesToNoFollow?: boolean;
   defaultOpenGraphImageWidth?: number;
   defaultOpenGraphImageHeight?: number;
   defaultOpenGraphVideoWidth?: number;
   defaultOpenGraphVideoHeight?: number;
 }
-
 export interface BuildTagsParams extends DefaultSeoProps, NextSeoProps {}


Test patch:
diff --git a/e2e/pages/overridden.tsx b/e2e/pages/overridden.tsx
index 87155e9..3772f41 100644
--- a/e2e/pages/overridden.tsx
+++ b/e2e/pages/overridden.tsx
@@ -6,6 +6,7 @@ export default () => (
   <>
     <NextSeo
       noindex={true}
+      nofollow={true}
       title="Title B"
       description="Description B"
       canonical="https://www.canonical.ie/b"
diff --git a/src/meta/__tests__/buildTags.spec.tsx b/src/meta/__tests__/buildTags.spec.tsx
index 485aff5..569698e 100644
--- a/src/meta/__tests__/buildTags.spec.tsx
+++ b/src/meta/__tests__/buildTags.spec.tsx
@@ -225,7 +225,7 @@ it('returns full array for default seo object', () => {
   expect(Array.from(canonicalTag).length).toBe(1);
 });
 
-it('correctly sets noindex, nofollow', () => {
+it('correctly sets noindex', () => {
   const overrideProps = {
     ...SEO,
     noindex: true,
@@ -233,14 +233,49 @@ it('correctly sets noindex, nofollow', () => {
   const tags = buildTags(overrideProps);
   const { container } = render(<>{React.Children.toArray(tags)}</>);
   const index = container.querySelectorAll('meta[content="index,follow"]');
-  const noindex = container.querySelectorAll(
-    'meta[content="noindex,nofollow"]',
-  );
+  const noindex = container.querySelectorAll('meta[content="noindex,follow"]');
 
   expect(Array.from(index).length).toBe(0);
   expect(Array.from(noindex).length).toBe(2);
 });
 
+it('correctly sets nofollow', () => {
+  const overrideProps = {
+    ...SEO,
+    nofollow: true,
+  };
+  const tags = buildTags(overrideProps);
+  const { container } = render(<>{React.Children.toArray(tags)}</>);
+  const indexfollow = container.querySelectorAll(
+    'meta[content="index,follow"]',
+  );
+  const indexnofollow = container.querySelectorAll(
+    'meta[content="index,nofollow"]',
+  );
+
+  expect(Array.from(indexfollow).length).toBe(0);
+  expect(Array.from(indexnofollow).length).toBe(2);
+});
+
+it('correctly sets noindex, nofollow', () => {
+  const overrideProps = {
+    ...SEO,
+    noindex: true,
+    nofollow: true,
+  };
+  const tags = buildTags(overrideProps);
+  const { container } = render(<>{React.Children.toArray(tags)}</>);
+  const indexfollow = container.querySelectorAll(
+    'meta[content="index,follow"]',
+  );
+  const noindexnofollow = container.querySelectorAll(
+    'meta[content="noindex,nofollow"]',
+  );
+
+  expect(Array.from(indexfollow).length).toBe(0);
+  expect(Array.from(noindexnofollow).length).toBe(2);
+});
+
 it('displays title with titleTemplate integrated', () => {
   const template = 'Next SEO';
   const overrideProps = {
@@ -749,27 +784,50 @@ it('correctly sets noindex default', () => {
   };
   const tags = buildTags(overrideProps);
   const { container } = render(<>{React.Children.toArray(tags)}</>);
-  const index = container.querySelectorAll('meta[content="index,follow"]');
-  const noindex = container.querySelectorAll(
+  const indexfollow = container.querySelectorAll(
+    'meta[content="index,follow"]',
+  );
+  const noindexfollow = container.querySelectorAll(
+    'meta[content="noindex,follow"]',
+  );
+
+  expect(Array.from(indexfollow).length).toBe(0);
+  expect(Array.from(noindexfollow).length).toBe(2);
+});
+
+it('correctly sets nofollow default', () => {
+  const overrideProps = {
+    ...SEO,
+    dangerouslySetAllPagesToNoFollow: true,
+  };
+  const tags = buildTags(overrideProps);
+  const { container } = render(<>{React.Children.toArray(tags)}</>);
+  const indexfollow = container.querySelectorAll(
+    'meta[content="index,follow"]',
+  );
+  const noindexnofollow = container.querySelectorAll(
     'meta[content="noindex,nofollow"]',
   );
 
-  expect(Array.from(index).length).toBe(0);
-  expect(Array.from(noindex).length).toBe(2);
+  expect(Array.from(indexfollow).length).toBe(0);
+  expect(Array.from(noindexnofollow).length).toBe(2);
 });
 
-it('correctly read noindex false', () => {
+it('correctly read noindex & nofollow false', () => {
   const overrideProps = {
     ...SEO,
     noindex: false,
+    nofollow: false,
   };
   const tags = buildTags(overrideProps);
   const { container } = render(<>{React.Children.toArray(tags)}</>);
-  const index = container.querySelectorAll('meta[content="index,follow"]');
-  const noindex = container.querySelectorAll(
+  const indexfollow = container.querySelectorAll(
+    'meta[content="index,follow"]',
+  );
+  const noindexnofollow = container.querySelectorAll(
     'meta[content="noindex,nofollow"]',
   );
 
-  expect(Array.from(index).length).toBe(2);
-  expect(Array.from(noindex).length).toBe(0);
+  expect(Array.from(indexfollow).length).toBe(0);
+  expect(Array.from(noindexnofollow).length).toBe(2);
 });