@@ -302,6 +383,7 @@ class EditorToolbar extends React.Component {
if (currentStatus) {
return (
<>
+ {this.renderDeployPreviewControls(t('editor.editorToolbar.deployPreviewButtonLabel'))}
{t('editor.editorToolbar.published')};
+ return (
+ <>
+ {this.renderDeployPreviewControls(t('editor.editorToolbar.deployButtonLabel'))}
+ {t('editor.editorToolbar.published')}
+ >
+ );
}
};
diff --git a/packages/netlify-cms-core/src/constants/configSchema.js b/packages/netlify-cms-core/src/constants/configSchema.js
index e6feb0cf..2229f18b 100644
--- a/packages/netlify-cms-core/src/constants/configSchema.js
+++ b/packages/netlify-cms-core/src/constants/configSchema.js
@@ -34,8 +34,10 @@ const getConfigSchema = () => ({
properties: { name: { type: 'string', examples: ['test-repo'] } },
required: ['name'],
},
+ site_url: { type: 'string', examples: ['https://example.com'] },
display_url: { type: 'string', examples: ['https://example.com'] },
logo_url: { type: 'string', examples: ['https://example.com/images/logo.svg'] },
+ show_preview_links: { type: 'boolean' },
media_folder: { type: 'string', examples: ['assets/uploads'] },
public_folder: { type: 'string', examples: ['/uploads'] },
media_library: {
@@ -86,7 +88,10 @@ const getConfigSchema = () => ({
required: ['name', 'label', 'file', 'fields'],
},
},
+ identifier_field: { type: 'string' },
slug: { type: 'string' },
+ preview_path: { type: 'string' },
+ preview_path_date_field: { type: 'string' },
create: { type: 'boolean' },
editor: {
type: 'object',
diff --git a/packages/netlify-cms-core/src/constants/defaultPhrases.js b/packages/netlify-cms-core/src/constants/defaultPhrases.js
index 975c6195..79114de0 100644
--- a/packages/netlify-cms-core/src/constants/defaultPhrases.js
+++ b/packages/netlify-cms-core/src/constants/defaultPhrases.js
@@ -78,6 +78,9 @@ export function getPhrases() {
inReview: 'In review',
ready: 'Ready',
publishNow: 'Publish now',
+ deployPreviewPendingButtonLabel: 'Check for Preview',
+ deployPreviewButtonLabel: 'View Preview',
+ deployButtonLabel: 'View Live',
},
editorWidgets: {
unknownControl: {
@@ -119,6 +122,7 @@ export function getPhrases() {
},
toast: {
onFailToLoadEntries: 'Failed to load entry: %{details}',
+ onFailToLoadDeployPreview: 'Failed to load preview: %{details}',
onFailToPersist: 'Failed to persist entry: %{details}',
onFailToDelete: 'Failed to delete entry: %{details}',
onFailToUpdateStatus: 'Failed to update status: %{details}',
diff --git a/packages/netlify-cms-core/src/constants/fieldInference.js b/packages/netlify-cms-core/src/constants/fieldInference.js
index 7f3c6680..d907d793 100644
--- a/packages/netlify-cms-core/src/constants/fieldInference.js
+++ b/packages/netlify-cms-core/src/constants/fieldInference.js
@@ -27,6 +27,14 @@ export const INFERABLE_FIELDS = {
fallbackToFirstField: false,
showError: false,
},
+ date: {
+ type: 'datetime',
+ secondaryTypes: ['date'],
+ synonyms: ['date', 'publishDate', 'publish_date'],
+ defaultPreview: value => value,
+ fallbackToFirstField: false,
+ showError: false,
+ },
description: {
type: 'string',
secondaryTypes: ['text', 'markdown'],
diff --git a/packages/netlify-cms-core/src/reducers/deploys.js b/packages/netlify-cms-core/src/reducers/deploys.js
new file mode 100644
index 00000000..e5580daa
--- /dev/null
+++ b/packages/netlify-cms-core/src/reducers/deploys.js
@@ -0,0 +1,45 @@
+import { Map, fromJS } from 'immutable';
+import {
+ DEPLOY_PREVIEW_REQUEST,
+ DEPLOY_PREVIEW_SUCCESS,
+ DEPLOY_PREVIEW_FAILURE,
+} from 'Actions/deploys';
+
+const deploys = (state = Map({ deploys: Map() }), action) => {
+ switch (action.type) {
+ case DEPLOY_PREVIEW_REQUEST: {
+ const { collection, slug } = action.payload;
+ return state.setIn(['deploys', `${collection}.${slug}`, 'isFetching'], true);
+ }
+
+ case DEPLOY_PREVIEW_SUCCESS: {
+ const { collection, slug, url, status } = action.payload;
+ return state.setIn(
+ ['deploys', `${collection}.${slug}`],
+ fromJS({
+ isFetching: false,
+ url,
+ status,
+ }),
+ );
+ }
+
+ case DEPLOY_PREVIEW_FAILURE: {
+ const { collection, slug } = action.payload;
+ return state.setIn(
+ ['deploys', `${collection}.${slug}`],
+ fromJS({
+ isFetching: false,
+ }),
+ );
+ }
+
+ default:
+ return state;
+ }
+};
+
+export const selectDeployPreview = (state, collection, slug) =>
+ state.getIn(['deploys', `${collection}.${slug}`]);
+
+export default deploys;
diff --git a/packages/netlify-cms-core/src/reducers/index.js b/packages/netlify-cms-core/src/reducers/index.js
index a5a44bb0..50228f96 100644
--- a/packages/netlify-cms-core/src/reducers/index.js
+++ b/packages/netlify-cms-core/src/reducers/index.js
@@ -9,6 +9,7 @@ import collections from './collections';
import search from './search';
import mediaLibrary from './mediaLibrary';
import medias, * as fromMedias from './medias';
+import deploys, * as fromDeploys from './deploys';
import globalUI from './globalUI';
const reducers = {
@@ -23,6 +24,7 @@ const reducers = {
entryDraft,
mediaLibrary,
medias,
+ deploys,
globalUI,
};
@@ -47,6 +49,9 @@ export const selectSearchedEntries = state => {
);
};
+export const selectDeployPreview = (state, collection, slug) =>
+ fromDeploys.selectDeployPreview(state.deploys, collection, slug);
+
export const selectUnpublishedEntry = (state, collection, slug) =>
fromEditorialWorkflow.selectUnpublishedEntry(state.editorialWorkflow, collection, slug);
diff --git a/packages/netlify-cms-ui-default/src/Icon/images/_index.js b/packages/netlify-cms-ui-default/src/Icon/images/_index.js
index 2bc93499..ffd8edf7 100644
--- a/packages/netlify-cms-ui-default/src/Icon/images/_index.js
+++ b/packages/netlify-cms-ui-default/src/Icon/images/_index.js
@@ -30,10 +30,12 @@ import iconMedia from './media.svg';
import iconMediaAlt from './media-alt.svg';
import iconNetlify from './netlify.svg';
import iconNetlifyCms from './netlify-cms-logo.svg';
+import iconNewTab from './new-tab.svg';
import iconPage from './page.svg';
import iconPages from './pages.svg';
import iconPagesAlt from './pages-alt.svg';
import iconQuote from './quote.svg';
+import iconRefresh from './refresh.svg';
import iconScroll from './scroll.svg';
import iconSearch from './search.svg';
import iconSettings from './settings.svg';
@@ -76,10 +78,12 @@ const images = {
'media-alt': iconMediaAlt,
netlify: iconNetlify,
'netlify-cms': iconNetlifyCms,
+ 'new-tab': iconNewTab,
page: iconPage,
pages: iconPages,
'pages-alt': iconPagesAlt,
quote: iconQuote,
+ refresh: iconRefresh,
scroll: iconScroll,
search: iconSearch,
settings: iconSettings,
diff --git a/packages/netlify-cms-ui-default/src/Icon/images/new-tab.svg b/packages/netlify-cms-ui-default/src/Icon/images/new-tab.svg
new file mode 100644
index 00000000..896e6b39
--- /dev/null
+++ b/packages/netlify-cms-ui-default/src/Icon/images/new-tab.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/netlify-cms-ui-default/src/Icon/images/refresh.svg b/packages/netlify-cms-ui-default/src/Icon/images/refresh.svg
new file mode 100644
index 00000000..658be99f
--- /dev/null
+++ b/packages/netlify-cms-ui-default/src/Icon/images/refresh.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/website/content/blog/deploy-preview-links.md b/website/content/blog/deploy-preview-links.md
new file mode 100644
index 00000000..68d57d31
--- /dev/null
+++ b/website/content/blog/deploy-preview-links.md
@@ -0,0 +1,65 @@
+---
+title: "Netlify CMS 2.4.0: Deploy Preview Links"
+author: Shawn Erquhart
+description: >-
+ Deploy preview links from your GitHub repository are now surfaced in Netlify
+ CMS for previewing builds of unpublished content.
+date: 2019-01-28T19:30:00.000Z
+twitter_image: /img/preview-link-unpublished.png
+---
+
+![Deploy preview link for unpublished content](/img/preview-link-unpublished.png)
+
+## Seeing is believing
+
+The editorial workflow allows editors to create draft content in Netlify CMS, and Netlify can
+provide deploy previews of draft content, but there hasn't been a way to access links to these
+preview builds from within Netlify CMS. The preview pane in the editor is a good tool for seeing how
+content will look on the site, but in the words of Marvin Gaye, "ain't nothing like the real thing!"
+As Mr. Gaye bemoaned the absence of his beloved, so content creators long for the warm embrace of an
+actual production build. Their words, not ours.
+
+## Solution: GitHub Statuses
+
+![GitHub statuses](/img/github-statuses-deploy-previews.png)
+
+For sites using the GitHub (or Git Gateway with GitHub) backend, we now have deploy preview links in
+the CMS using the [GitHub Statuses
+API](https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref).
+Many static sites already have continuous deployment and deploy previews configured on their repo,
+and they often use statuses to provide a link to a deployment directly from a commit or pull
+request. To retrieve a commit status that provides a deploy preview URL, we check for a status whose
+"context" contains one of a list of keywords commonly associated with deploy previews.
+
+If a status is not found, nothing happens in the UI. If a status is found, but the deploy preview
+isn't ready, we provide a "Check for Preview" link, allowing the content editor to manually check
+back until the preview is ready:
+
+![Deploy preview link for unpublished content](/img/preview-link-check.png)
+
+When the preview is ready, the "Check for Preview" button is replaced with a link to the content:
+
+![Deploy preview link for unpublished content](/img/preview-link-unpublished.png)
+
+## Deep links
+Deploy preview links generally direct to the root of a site, but Netlify CMS can also link straight
+to the piece of content being edited. By [providing a string template](/docs/deploy-preview-links)
+for each collection, you can get links that go right where editors expect them to. More complex
+URL's can be constructed [using date
+information](/docs/deploy-preview-links/#dates-in-preview-paths) from your content files.
+
+## Unpublished vs. published
+If you're not using the editorial workflow, you may not feel you need this very much. Whenever you
+save content, it's immediatlely published, so you can navigate to your live site to see the changes.
+That said, it's at least convenient to have a link direct to your content from the CMS, so deploy
+preview links can also work for CMS installs that do not use the editorial workflow. Instead of
+retrieving a URL from a commit status, this functionality requires setting a `site_url` in your
+config, and that URL is used in place of the deploy preview URL.
+
+## GitLab and Bitbucket
+Support is coming soon for these two awesome backends! Stay tuned.
+
+## Try it out!
+Deploy preview links are live in Netlify CMS 2.4.0. Please give them a try and let us know if you
+have any problems by [opening an issue](https://github.com/netlify/netlify-cms/issues/new) or
+reaching out in our [community chat on Gitter](https://gitter.im/netlify/netlifycms)!
diff --git a/website/content/docs/authentication-backends.md b/website/content/docs/authentication-backends.md
index c203040c..2b9087be 100644
--- a/website/content/docs/authentication-backends.md
+++ b/website/content/docs/authentication-backends.md
@@ -6,6 +6,9 @@ group: start
Netlify CMS stores content in your GitHub, GitLab, or Bitbucket repository. In order for this to work, authenticate with your Git host. In most cases that requires a server. We have a few options for handling this.
+
+**Note:** If you prefer to run your own authentication server, check out the section on [external OAuth clients](#external-oauth-clients).
+
**Note:** Some static site generators have plugins for optimized integration with Netlify CMS, and starter templates may utilize these plugins. If you're using a starter template, read the template documentation before proceeding, as their instructions may differ.
## Git Gateway with Netlify Identity
@@ -54,7 +57,20 @@ To enable basic GitHub authentication:
repo: owner-name/repo-name # Path to your GitHub repository
```
-If you prefer to run your own authentication server, check out the section on [external OAuth clients](#external-oauth-clients).
+### Specifying a status for deploy previews
+The GitHub backend supports [deploy preview links](../deploy-preview-links). Netlify CMS checks the
+`context` of a commit's [statuses](https://help.github.com/articles/about-status-checks/) and infers
+one that seems to represent a deploy preview. If you need to customize this behavior, you can
+specify which context to look for using `preview_context`:
+
+ ```yaml
+ backend:
+ name: github
+ repo: my/repo
+ preview_context: my-provider/deployment
+ ```
+
+The above configuration would look for the status who's `"context"` is `"my-provider/deployment"`.
## GitLab Backend
diff --git a/website/content/docs/cloudinary.md b/website/content/docs/cloudinary.md
index b67d61fb..4e2c42a6 100644
--- a/website/content/docs/cloudinary.md
+++ b/website/content/docs/cloudinary.md
@@ -1,7 +1,7 @@
---
title: Cloudinary
group: media
-weight: '10'
+weight: 10
---
Cloudinary is a digital asset management platform with a broad feature set, including support for responsive image generation and url based image transformation. They also provide a powerful media library UI for managing assets, and tools for organizing your assets into a hierarchy.
diff --git a/website/content/docs/configuration-options.md b/website/content/docs/configuration-options.md
index 7068fff1..3a9705a8 100644
--- a/website/content/docs/configuration-options.md
+++ b/website/content/docs/configuration-options.md
@@ -85,10 +85,24 @@ media_library:
publicKey: demopublickey
```
+## Site URL
+
+The `site_url` setting should provide a URL to your published site. May be used by the CMS for
+various functionality. Used together with a collection's `preview_path` to create links to live
+content.
+
+**Example:**
+
+```yaml
+display_url: https://your-site.com
+```
+
## Display URL
When the `display_url` setting is specified, the CMS UI will include a link in the fixed area at the top of the page, allowing content authors to easily return to your main site. The text of the link consists of the URL less the protocol portion (e.g., `your-site.com`).
+Defaults to `site_url`.
+
**Example:**
```yaml
@@ -105,6 +119,16 @@ When the `logo_url` setting is specified, the CMS UI will change the logo displa
logo_url: https://your-site.com/images/logo.svg
```
+## Show Preview Links
+
+[Deploy preview links](../deploy-preview-links) can be disabled by setting `show_preview_links` to `false`.
+
+**Example:**
+
+```yaml
+show_preview_links: false
+```
+
## Slug Type
The `slug` option allows you to change how filenames for entries are created and sanitized. For modifying the actual data in a slug, see the per-collection option below.
@@ -135,6 +159,7 @@ The `collections` setting is the heart of your Netlify CMS configuration, as it
`collections` accepts a list of collection objects, each with the following options:
- `name` (required): unique identifier for the collection, used as the key when referenced in other contexts (like the [relation widget](../widgets/#relation))
+- `identifier_field`: see detailed description below
- `label`: label for the collection in the editor UI; defaults to the value of `name`
- `label_singular`: singular label for certain elements in the editor; defaults to the value of `label`
- `description`: optional text, displayed below the label when viewing a collection
@@ -146,11 +171,27 @@ The `collections` setting is the heart of your Netlify CMS configuration, as it
- `format`: see detailed description below
- `frontmatter_delimiter`: see detailed description under `format`
- `slug`: see detailed description below
+- `preview_path`: see detailed description below
- `fields` (required): see detailed description below
- `editor`: see detailed description below
The last few options require more detailed information.
+### `identifier_field`
+
+Netlify CMS expects every entry to provide a field named `"title"` that serves as an identifier for
+the entry. The identifier field serves as an entry's title when viewing a list of entries, and is
+used in [slug](#slug) creation. If you would like to use a field other than `"title"` as the
+identifier, you can set `identifier_field` to the name of the other field.
+
+**Example**
+
+``` yaml
+collections:
+ - name: posts
+ identifier_field: name
+```
+
### `extension` and `format`
These settings determine how collection files are parsed and saved. Both are optional—Netlify CMS will attempt to infer your settings based on existing items in the collection. If your collection is empty, or you'd like more control, you can set these fields explicitly.
@@ -174,11 +215,11 @@ You may also specify a custom `extension` not included in the list above, as lon
### `slug`
-For folder collections where users can create new items, the `slug` option specifies a template for generating new filenames based on a file's creation date and `title` field. (This means that all collections with `create: true` must have a `title` field.)
+For folder collections where users can create new items, the `slug` option specifies a template for generating new filenames based on a file's creation date and `title` field. (This means that all collections with `create: true` must have a `title` field (a different field can be used via [`identifier_field`](#identifier_field)).
**Available template tags:**
-- `{{slug}}`: a url-safe version of the `title` field for the file
+- `{{slug}}`: a url-safe version of the `title` field (or identifier field) for the file
- `{{year}}`: 4-digit year of the file creation date
- `{{month}}`: 2-digit month of the file creation date
- `{{day}}`: 2-digit day of the month of the file creation date
@@ -192,6 +233,48 @@ For folder collections where users can create new items, the `slug` option speci
slug: "{{year}}-{{month}}-{{day}}_{{slug}}"
```
+
+### `preview_path`
+A string representing the path where content in this collection can be found on the live site. This
+allows deploy preview links to direct to lead to a specific piece of content rather than the site
+root of a deploy preview.
+
+**Available template tags:**
+
+- Any field can be referenced by wrapping the field name in double curly braces, eg. `{{author}}`
+- `{{slug}}`: the entire slug for the current entry (not just the url-safe identifier, as is the
+ case with [`slug` configuration](#slug)
+
+The following date based template tags are pulled from a date field in your entry, and may require additional configuration, see [`preview_path_date_field`](#preview_path_date_field) for details. If a date template tag is used and no date can be found, `preview_path` will be ignored.
+
+- `{{year}}`: 4-digit year from entry data
+- `{{month}}`: 2-digit month from entry data
+- `{{day}}`: 2-digit day of the month from entry data
+- `{{hour}}`: 2-digit hour from entry data
+- `{{minute}}`: 2-digit minute from entry data
+- `{{second}}`: 2-digit second from entry data
+
+**Example:**
+```yaml
+collections:
+ - name: posts
+ preview_path: "blog/{{year}}/{{month}}/{{slug}}"
+```
+
+### `preview_path_date_field`
+The name of a date field for parsing date-based template tags from `preview_path`. If this field is
+not provided and `preview_path` contains date-based template tags (eg. `{{year}}`), Netlify CMS will
+attempt to infer a usable date field by checking for common date field names, such as `date`. If you
+find that you need to specify a date field, you can use `preview_path_date_field` to tell Netlify
+CMS which field to use for preview path template tags.
+
+**Example:**
+```yaml
+collections:
+ - name: posts
+ preview_path_date_field: "updated_on"
+```
+
### `fields`
The `fields` option maps editor UI widgets to field-value pairs in the saved file. The order of the fields in your Netlify CMS `config.yml` file determines their order in the editor UI and in the saved file.
diff --git a/website/content/docs/deploy-preview-links.md b/website/content/docs/deploy-preview-links.md
new file mode 100644
index 00000000..450c4294
--- /dev/null
+++ b/website/content/docs/deploy-preview-links.md
@@ -0,0 +1,139 @@
+---
+title: Deploy Preview Links
+group: features
+weight: 10
+---
+
+When using the editorial workflow, content editors can create and save content without publishing it
+to a live site. Deploy preview links provide a way to view live content when it has not been
+published, provided that you're using a continuous deployment platform to provide "deploy previews"
+of your unmerged content.
+
+**Note:** for the initial release, only the GitHub and Git Gateway (with GitHub) backends will
+support deploy preview links. Others should follow shortly.
+
+## Using deploy preview links
+Deploy preview links will work without configuration when all of the following requirements are met:
+
+- Netlify CMS version is 2.4.0+
+- Using the GitHub backend (or Git Gateway with a GitHub repository)
+- Using editorial workflow
+- Have a continous deployment platform that builds every commit and provides statuses to your repo
+
+Any site created using one of the Deploy to Netlify options on our [starters
+page](../start-with-a-template) will automatically meet these criteria (barring any changes made to
+your Netlify settings), but you may need to [update](../update-the-cms-version) your Netlify CMS version to get the
+functionality.
+
+**Note:** If you're using a custom backend (one that is not included with Netlify CMS), please check the
+documentation for that backend for more information about enabling deploy preview links.
+
+Deploy preview links are provided in the editor toolbar, near the publishing controls:
+
+![Deploy preview link for unpublished content](/img/preview-link-unpublished.png)
+
+### Waiting for builds
+Deploy your site preview may take ten seconds or ten minutes, depending on many factors. For maximum
+flexibility, Netlify CMS provides a "Check for Preview" refresh button when the deploy preview is
+pending, which a content editor can use to manually check for a finished preview until it's ready:
+
+![Deploy preview link for unpublished content](/img/preview-link-check.png)
+
+## Configuring preview paths
+Deploy preview links point to the site root by default, but you'll probably want them to point to
+the specific piece of content that the content editor is viewing. You can do this by providing a
+`preview_path` string template for each collection.
+
+Let's say we have a `blog` collection that stores content in our repo under `content/blog`. The path
+to a post in your repo may look like `content/blog/2018-01-new-post.md`, but the path to that post
+on your site would look more like: `/blog/2018-01-new-post/`. Here's how you would use
+`preview_path` in your configuration for this scenario:
+
+```yml
+collections:
+ - name: blog
+ folder: content/blog
+ slug: {{year}}-{{month}}-{{slug}}
+ preview_path: blog/{{slug}}
+```
+
+With the above configuration, the deploy preview URL from your backend will be combined with your
+preview path to create a URL to a specific blog post.
+
+**Note:** `{{slug}}` in `preview_path` is different than `{{slug}}` in `slug`. In the `slug`
+template, `{{slug}}` is only the url-safe [identifier
+field](../configuration-options/#identifier_field), while in the `preview_path` template, `{{slug}}`
+is the entire slug for the entry. For example:
+
+```yml
+# for an entry created Jan 1, 2000 with identifier "My New Post!"
+
+collections:
+ - name: posts
+ slug: {{year}}-{{month}}-{{slug}} # {{slug}} will compile to "my-new-post"
+ preview_path: blog/{{slug}} # {{slug}} will compile to "2000-01-my-new-post"
+```
+
+### Dates in preview paths
+Some static site generators allow URL's to be customized with date parameters - for example, Hugo
+can be configured to use values like `year` and `month` in a URL. These values are generally derived
+by the static site generator from a date field in the content file. `preview_path` accepts these
+parameters as well, similar to the `slug` configuration, except `preview_path` populates date values
+based on a date value from the entry, just like static site generators do. Netlify CMS will attempt
+to infer an obvious date field, but you can also specify which date field to use for `preview_path`
+template tags by using
+[`preview_path_date_field`](../configuration-options/#preview_path_date_field).
+
+Together with your other field values, dates can be used to configure most URL schemes available
+through static site generators.
+
+**Example**
+
+```yaml
+# This collection's date field will be inferred because it has a field named `"date"`
+
+collections:
+ - name: posts
+ preview_path: blog/{{year}}/{{month}}/{{title}}
+ fields:
+ - { name: title, label: Title }
+ { name: date, label: Date, widget: date }
+ { name: body, label: Body, widget: markdown }
+
+# This collection requires `path_preview_date_field` because the no obvious date field is available
+
+collections:
+ - name: posts
+ preview_path: blog/{{year}}/{{month}}/{{title}}
+ preview_path_date_field: published_at
+ fields:
+ - { name: title, label: Title }
+ { name: published_at, label: Published At, widget: date }
+ { name: body, label: Body, widget: markdown }
+```
+
+## Preview links for published content
+You may also want preview links for published content as a convenience. You can do this by providing
+a `site_url` in your configuration, which will be used in place of the deploy preview URL that a
+backend would provide for an unpublished entry. Just as for deploy preview links to unpublished
+content, inks to published content will use any `preview_path` values that are defined in the
+collection configurations.
+
+Preview links for published content will also work if you are not using the editorial workflow.
+
+![Deploy preview link for unpublished content](/img/preview-link-unpublished.png)
+
+## Disabling deploy preview links
+To disable deploy preview links, set `show_preview_links` to false in your CMS configuration.
+
+## How it works
+Deploy preview links are provided through your CMS backend, and Netlify CMS is unopinionated about
+where the links come from or how they're created. That said, the general approach for Git backends
+like GitHub is powered by "commit statuses". Continuous deployment platforms like Netlify can deploy
+a version of your site for every commit that is pushed to your remote Git repository, and then send
+a commit status back to your repository host with the URL.
+
+The deploy preview URL provided by a backend will lead to the root of the deployed site. Netlify CMS
+will then use the `preview_path` template in an entry's collection configuration to build a path to
+a specific piece of content. If a `preview_path` is not provided for an entry's collection, the URL
+will be used as is.
diff --git a/website/gatsby-config.js b/website/gatsby-config.js
index fa998383..1d75f761 100644
--- a/website/gatsby-config.js
+++ b/website/gatsby-config.js
@@ -11,6 +11,10 @@ module.exports = {
name: 'start',
title: 'Quick Start',
},
+ {
+ name: 'features',
+ title: 'Features',
+ },
{
name: 'reference',
title: 'Reference',