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

Make sluggification visible, customizable, and fail-safe #445

Open
erquhart opened this issue Jun 6, 2017 · 40 comments
Open

Make sluggification visible, customizable, and fail-safe #445

erquhart opened this issue Jun 6, 2017 · 40 comments

Comments

@erquhart
Copy link
Member

@erquhart erquhart commented Jun 6, 2017

Default sluggification is simplistic, relying on a title field and performing no inference whatsoever.

With no field named "title", entries currently fail to save.

The ideal fix is to simply make slugs editable in the editor UI.

Considerations:

  • Slug editing can be switched off through config
  • If slug editing is switched off, each collection config must be validated on CMS load to ensure a slug can be derived
  • Prepopulate with the same best guess or configured slug template result that we currently use
  • Only valid characters may be entered in the slug field
  • Slugs and filenames are not always the same, so it should be possible to provide them separately somehow (see comment below for example)
@Benaiah
Copy link
Contributor

@Benaiah Benaiah commented Jun 6, 2017

@erquhart how does the slug entry in collections affect sluggification - is it functional anymore? (I've been working under the assumption that the current behavior is that the title field is sluggified and turned into the {{slug}} part of the slug template).

@erquhart
Copy link
Member Author

@erquhart erquhart commented Jun 6, 2017

Yep, that's the default behavior, but date segments can be used for some light slug templating:

const slugFormatter = (template = "{{slug}}", entryData) => {
const date = new Date();
const identifier = entryData.get("title", entryData.get("path"));
return template.replace(/\{\{([^\}]+)\}\}/g, (_, field) => {
switch (field) {
case "year":
return date.getFullYear();
case "month":
return (`0${ date.getMonth() + 1 }`).slice(-2);
case "day":
return (`0${ date.getDate() }`).slice(-2);
case "slug":
return slug(identifier.trim(), {lower: true});
default:
return slug(entryData.get(field, "").trim(), {lower: true});
}
});
};

@erquhart erquhart mentioned this issue Jun 28, 2017
0 of 2 tasks complete
@erquhart erquhart added this to the 1.0 milestone Jun 28, 2017
@erquhart
Copy link
Member Author

@erquhart erquhart commented Jun 28, 2017

May happen in tandem with #180.

@tech4him1
Copy link
Contributor

@tech4him1 tech4him1 commented Sep 19, 2017

We currently overwrite any existing entry when a new entry is created that has the same slug. This is probably best fixed along with this issue.

@tech4him1
Copy link
Contributor

@tech4him1 tech4him1 commented Sep 20, 2017

I also think we should throw an error if the slug is going to be blank.

@aperep
Copy link

@aperep aperep commented Sep 20, 2017

It is a bad idea to silently overwrite entries. If a user creates multiple entries on same day and does not bother about titles, then all entries except last will be lost without any notification. This is easily the worst imaginable behaviour.

@erquhart erquhart removed the priority/P2 label Dec 8, 2017
@t1merickson
Copy link

@t1merickson t1merickson commented Dec 17, 2017

I wonder if we should change or prioritize how we visualize the 'title' field to imply it's importance

@erquhart erquhart removed the help wanted label Dec 19, 2017
@erquhart
Copy link
Member Author

@erquhart erquhart commented Dec 22, 2017

We're actually looking to eliminate it's importance. Right now it's critical because it's used for automated slug creation, which the user can't see or influence. This issue calls for making slug creation interactive. We could pre-fill with whatever's in a title field, but if there's no field (or the slug is blank for any other reason), the entry would fail validation and could not be saved.

@bjrn
Copy link
Contributor

@bjrn bjrn commented Feb 16, 2018

Hi! What's the status on slug editing, anyone working on a suggestion?

@erquhart
Copy link
Member Author

@erquhart erquhart commented Feb 13, 2019

Update:

Some SSG's, like Jekyll, respect a slug value in the frontmatter. Until recently the {{slug}} built in placeholder made it impossible to reference a field named slug in your slug configuration, but as of Netlify CMS 2.4.2 you can now do {{fields.slug}} to reference a field by that name. That means you can control your filename in a predictable way:

collections:
  - name: posts
    folder: posts
    slug: {{fields.slug}}
    fields:
      - {name: title, label: Title}
      - {name: slug, label: Slug}
      - {name: body, label: Body, widget: markdown}

Note: this does not provide any way to change the filename after the initial save.

It's manual, but it's technically a minimum viable approach that satisfies the goals of this issue:

  • Visible: just a field
  • Customizable: can be a combination of fields via slug config
  • Fail-safe: the field value is sanitized and sluggified, and same-named files are rejected at the API level

We should keep the issue open for a more automated approach that's workable for non-technical editors, but this is at least a good stop gap for folks that need it.

@erodrig
Copy link

@erodrig erodrig commented Mar 10, 2019

@erquhart that approach do not allow the field to be sluggified automatically from the title, it will need to be manually set each time. Can you please confirm. Ideally the field should be visible and updated once the title is set, but in this case if is empty it will fail, and will force manual entry.
In a different note, without talking about slug update, it will be nice to be able to create a field with the contents of the slug field just like path : "/example/{{slug}}"

@erquhart
Copy link
Member Author

@erquhart erquhart commented Mar 10, 2019

@erodrig yep, just providing a newly available stopgap. Issue remains open for an automated solution.

Sent with GitHawk

@srsgores
Copy link

@srsgores srsgores commented Mar 22, 2019

What's the status on this? Can anyone provide an update? Is it at all possible to save the relation value as the slug?

@erquhart
Copy link
Member Author

@erquhart erquhart commented Apr 2, 2019

That's always been possible, just use the name of your relation field in the slug template. Let's say you have a relation field named "relation", your slug template would be {{relation}}.

@verythorough
Copy link
Contributor

@verythorough verythorough commented Jun 21, 2019

Tied this to #1767, because files without frontmatter have their own particular sluggification issues.

@stale
Copy link

@stale stale bot commented Oct 29, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@adrian5
Copy link
Contributor

@adrian5 adrian5 commented Feb 1, 2020

I want to point out that the introduction of the path parameter introduces the problem of how to handle slug/frontmatter changes after the first save. E.g. /pages/{:year}/entry.md or /roster/{:team}/player.md remain at their current location, even if the dynamic portion of their path changes.

@erezrokah
Copy link
Collaborator

@erezrokah erezrokah commented Feb 2, 2020

Hi @adrian5, thank you for pointing this out. I think the issue you mentioned is already present with the slug configuration as you could do slug: {{year}}-{{title}} but probably more prominent when using path.

@hanneskuettner
Copy link
Contributor

@hanneskuettner hanneskuettner commented Apr 30, 2020

I stumbled across this issue myself.
Now that the config, entry data and collection is available to all control widgets (#3672) I was able to implement a custom slug control widget that allows the following:

... # whatever collection
- slug: '{{field.slug}}'
- fields:
  - name: title
     label: Title
     widget: string
  - name: slug
     label: Slug
     widget: slug
     slug: 'custom-slug-{{title}}'
  • Have a slug value field with a custom slug widget (that's basically a string widget) that can be used for the entry slug with fields.slug
  • The value in slug is automatically updated and correctly slugified according to the slug pattern and the root slug configuration
  • Once an entry is saved the slug is no longer updated when the dependent fields are updated
  • The user can manually update the slug but receives a warning that this might break existing URLs since it is a slug field

This works very well for me (I think at least). It still does not provide a way for a user to forcefully update the filename through the slug though.

Once it is a bit more polished I will open a PR (in the next few days) and then I would love to continue this discussion.

@keegan-lillo
Copy link
Contributor

@keegan-lillo keegan-lillo commented Sep 3, 2020

@hanneskuettner I look forward to your PR. In the mean time, I came up with a fairly decent solution that might help others.

I used Nested Collections to basically give me the same effect since the slug (file name) is set via the meta.path field.

config.yaml

collections:
  - name: 'pages'
    create: true
    label: 'Page'
    folder: 'src/content/pages'
    nested: { depth: 100, summary: '{{meta.path}}' }
    meta: { path: { widget: string, label: 'Path', index_file: 'index' } }
    fields:
      - label: 'Title'
        name: 'title'
        widget: 'string'

      - label: 'Body'
        name: 'body'
        widget: 'markdown'

And then if I add two items in the collection with paths set to: dir-a/dir-b/item-a and dir-a/dir-c/item-b
This results in a src/content/pages directory looking like:

src/content/pages:
  dir-a:
    dir-b:
      item-a:
        - index.md
    dir-c:
      item-b:
        - index.md

image

I'm using Gatsby so it's reasonably straightforward to generate slugs at build time using the technique from this guide.

@mikestopcontinues
Copy link

@mikestopcontinues mikestopcontinues commented Sep 24, 2020

Here's the thing: Without keeping the filename in sync with the slug, it's impossible to look up a single post without parsing the frontmatter of all files in the same collection. E.g., if my app wants the post with slug what-a-nice-post, the app needs to load all of the posts into memory. This kinda sucks when used alongside NextJS, which supports incremental static generation as well as incremental cache invalidation.

For this reason—and since URL slugs must be unique anyway—I think it makes more sense to update the filename whenever the slug changes.

Regarding how and when the slug changes, I like @hanneskuettner approach. The slug should stop auto-updating once the document is published (which happens at varying times depending on if you use the editorial workflow). After that, a notice is fair, as well as preventing a user from overwriting another file or making a change that would cause merge errors (if there are multiple editorial edits open on the file that would be renamed).

Honestly, I think Wordpress really nails their slug behavior, especially in cases where extra bits are added to the complete path. #377 has a screenshot that at least partly shows this behavior.

@hanneskuettner If you would, I'd very much appreciate seeing your work on that slug field. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Priority Issues
Needs Planning
2.0 Release
  
Requested
Linked pull requests

Successfully merging a pull request may close this issue.

None yet