From ff8dfac813eefca82a53670454ca359c50ad43b2 Mon Sep 17 00:00:00 2001 From: Shawn Erquhart Date: Tue, 12 Feb 2019 16:59:53 -0500 Subject: [PATCH] feat(core): allow field name to override slug placeholders (#2087) --- packages/netlify-cms-core/src/backend.js | 21 +++++++++--- website/content/docs/configuration-options.md | 32 +++++++++++-------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/packages/netlify-cms-core/src/backend.js b/packages/netlify-cms-core/src/backend.js index 620efc17..e71b9ca6 100644 --- a/packages/netlify-cms-core/src/backend.js +++ b/packages/netlify-cms-core/src/backend.js @@ -62,18 +62,31 @@ const dateParsers = { }; const SLUG_MISSING_REQUIRED_DATE = 'SLUG_MISSING_REQUIRED_DATE'; +const USE_FIELD_PREFIX = 'fields.'; + +// Allow `fields.` prefix in placeholder to override built in replacements +// like "slug" and "year" with values from fields of the same name. +function getExplicitFieldReplacement(key, data) { + if (!key.startsWith(USE_FIELD_PREFIX)) { + return; + } + const fieldName = key.substring(USE_FIELD_PREFIX.length); + return data.get(fieldName, '').trim(); +} function compileSlug(template, date, identifier = '', data = Map(), processor) { let missingRequiredDate; const slug = template.replace(/\{\{([^}]+)\}\}/g, (_, key) => { let replacement; - if (dateParsers[key] && !date) { + const explicitFieldReplacement = getExplicitFieldReplacement(key, data); + + if (explicitFieldReplacement) { + replacement = explicitFieldReplacement; + } else if (dateParsers[key] && !date) { missingRequiredDate = true; return ''; - } - - if (dateParsers[key]) { + } else if (dateParsers[key]) { replacement = dateParsers[key](date); } else if (key === 'slug') { replacement = identifier.trim(); diff --git a/website/content/docs/configuration-options.md b/website/content/docs/configuration-options.md index db076b42..971aa81e 100644 --- a/website/content/docs/configuration-options.md +++ b/website/content/docs/configuration-options.md @@ -213,8 +213,13 @@ You may also specify a custom `extension` not included in the list above, as lon 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:** +The slug template can also reference a field value by name, eg. `{{title}}`. If a field name +conflicts with a built in template tag name - for example, if you have a field named `slug`, and +would like to reference that field via `{{slug}}`, you can do so by adding the explicit `fields.` +prefix, eg. `{{fields.slug}}`. +**Available template tags:** +* Any field can be referenced by wrapping the field name in double curly braces, eg. `{{author}}` * `{{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 @@ -224,11 +229,20 @@ For folder collections where users can create new items, the `slug` option speci * `{{second}}`: 2-digit second of the file creation date **Example:** - ```yaml slug: "{{year}}-{{month}}-{{day}}_{{slug}}" ``` +**Example using field names:** +```yaml +slug: "{{year}}-{{month}}-{{day}}_{{title}}_{{some_other_field}}" +``` + +**Example using field name that conflicts with a template tag:** +```yaml +slug: "{{year}}-{{month}}-{{day}}_{{fields.slug}}" +``` + ### `preview_path` A string representing the path where content in this collection can be found on the live site. This @@ -237,18 +251,10 @@ 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 +Template tags are the same as those for [slug](#slug), with the following exceptions: +* `{{slug}}` is 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 +* The date based template tags, such as `{{year}}` and `{{month}}`, 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. **Example:**