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

Add permalinks tokens contentbasename and contentbasenameorslug #11722

Closed
hacdias opened this issue Nov 21, 2023 · 16 comments · Fixed by #13402
Closed

Add permalinks tokens contentbasename and contentbasenameorslug #11722

hacdias opened this issue Nov 21, 2023 · 16 comments · Fixed by #13402
Milestone

Comments

@hacdias
Copy link
Contributor

hacdias commented Nov 21, 2023

What version of Hugo are you using (hugo version)?

$ hugo version
hugo v0.120.4-f11bca5fec2ebb3a02727fb2a5cfb08da96fd9df+extended darwin/arm64 BuildDate=2023-11-08T11:18:07Z VendorInfo=brew

Does this issue reproduce with the latest release?

  1. Create a categories taxonomy.
  2. Create file /categories/a/_index.md and /categories/b/_index.md
  3. Create posts for those categories.
  4. Add the following to your config:
[permalinks]
  categories = '/:filename/'

All categories will be concurrently built to /index.html, which leads me to believe that :filename is empty for them.

@jmooring
Copy link
Member

/categories/a/_index.md and /categories/b/_index.md

Both filenames are _index.md. Not sure why you would want to do this. Seems like you want this instead:

[permalinks.term]
categories = '/:slug/'

@hacdias
Copy link
Contributor Author

hacdias commented Nov 22, 2023

@jmooring for other files, :filename is filled up with their directory name. I have the following rule:

posts = '/:year/:month/:day/:filename/'

And the post at posts/2023/distributed-tracing-with-opentelemetry/index.md will be published at:

/2023/04/18/distributed-tracing-with-opentelemetry/ (using the date in the frontmatter).

If it works for posts, why doesn't it work for categories?

I want the name attributed to that entry. Whether it is a directory entry of just a markdown file, it should not matter. You can see the source here: https://github.com/hacdias/hacdias.com

I wanted the categories to also use the disk name without me having to define a manual slug and not be dependent on the title, just like the posts.

@bep
Copy link
Member

bep commented Nov 22, 2023

Assuming you have files backing these categories, I don't see how they should behave differently.

But I see this in your config, which does not match your expectations:

[permalinks]
  tags = '/tags/:title/'
  categories = '/:title/'
  posts = '/:year/:month/:day/:filename/'

Also, I suspect that :slugorfilename may be a better option.

@bep bep added this to the v0.121.0 milestone Nov 22, 2023
@hacdias
Copy link
Contributor Author

hacdias commented Nov 22, 2023

@bep

But I see this in your config, which does not match your expectations:

I want to change to categories = '/:filename/'. But if I do that, it will all concurrently build to /index.html instead of to /:filename/index.html. Feel free to clone my repo, replacing that and building to see. All categories have a matching file.

@jmooring
Copy link
Member

jmooring commented Nov 27, 2023

// pageToPermalinkFilename returns the URL-safe form of the filename
func (l PermalinkExpander) pageToPermalinkFilename(p Page, _ string) (string, error) {
name := l.translationBaseName(p)
if name == "index" {
// Page bundles; the directory name will hopefully have a better name.
dir := strings.TrimSuffix(p.File().Dir(), helpers.FilePathSeparator)
_, name = filepath.Split(dir)
} else if name == "_index" {
return "", nil
}
return l.urlize(name), nil
}

Examining the above, the :filename token is limited to kind page. Before leaf bundles were introduced, "filename" was an accurate description. Then we introduced leaf bundles, and "filename" became either the file name or the directory name, but was still limited to kind page.

To avoid a breaking change, I suggest that we add a :contentbasename token.

ContentBaseName: If the page is a branch or leaf bundle, the name of the containing directory, else the TranslationBaseName.

@hacdias
Copy link
Contributor Author

hacdias commented Nov 27, 2023

That's interesting and looks like the source of the problem. I'm not sure that introducing :contentbasename is necessary though: is it a breaking change, or a bug? It doesn't seem likely to me that someone is using :filename for taxonomies if the current behaviour is that it won't work.

Whatever is done, I think the documentation should be clarified: https://gohugo.io/content-management/urls/#tokens

@jmooring
Copy link
Member

jmooring commented Nov 27, 2023

I'm not sure that introducing :contentbasename is necessary

  1. Changing the meaning of :filename may change some sites. I've been bitten by the "doesn't seem likely to me" assumption a few times, and there are some ugly and unexpected configs in the wild.
  2. The word "filename" was once an accurate description, but is has not been accurate for a long time. This is an opportunity to clean that up, using the same language we use elsewhere. And maybe we can deprecate :filename at some point.

Other considerations...

In most cases taxonomy terms are not backed by a file, so should :contentbasename fall back to the urlized title? If it doesn't, this will result in missing term pages when terms are not backed by a file:

[permalinks]
categories = '/:contentbasename'

We have a :slugorfilename token, so it seems like we'd want :slugorcontentbasename too... yuck

@jmooring jmooring changed the title Permalink :filename is empty for taxonomies Add :contentbasename permalink token Nov 27, 2023
@jmooring jmooring changed the title Add :contentbasename permalink token Add :contentbasename permalinks token Nov 27, 2023
jmooring added a commit to jmooring/hugo that referenced this issue Dec 4, 2023
@bep bep modified the milestones: v0.121.0, v0.122.0 Dec 6, 2023
@bep bep modified the milestones: v0.122.0, v0.123.0, v0.124.0 Jan 27, 2024
@bep bep modified the milestones: v0.124.0, v0.125.0 Mar 4, 2024
@jmooring
Copy link
Member

jmooring commented May 3, 2024

While updating https://gohugo.io/content-management/urls/#tokens to match current behavior, adding exceptions to the documentation is clumsy and a bit convoluted (e.g., "This applies to xxx but not to yyy.").

I think we should:

  1. Add a :contentbasename token that returns the File.ContentBaseName for all page kinds, not just limited to page.
  2. Add a :contentbasenameorslug token that applies to all page kinds, not just limited to page.
  3. Deprecate :filename because File.Filename is something different (the absolute file path), and to me the tokens should be symmetrical with the File.xxx names.

@bep I would appreciate it if you would (a) close this as "won't fix", (b) reclassify it as enhancement, or (c) comment with recommended changes. Thanks.

I'm pretty sure the current token implementation predates the File.ContentBaseName implementation.

@jmooring jmooring changed the title Add :contentbasename permalinks token Add permalinks tokens contentbasename and contentbasenameorslug May 3, 2024
@bep bep removed this from the v0.125.0 milestone Jul 22, 2024
@bep bep removed the NeedsTriage label Jul 22, 2024
@bep bep modified the milestones: v0.130.0, v0.131.0 Jul 30, 2024
@bep bep modified the milestones: v0.131.0, v0.133.0 Aug 9, 2024
@bep bep modified the milestones: v0.133.0, Unscheduled Aug 29, 2024
hacdias added a commit to hacdias/hacdias.com that referenced this issue Feb 10, 2025
Changed categories to work with slugs instead. Otherwise it wouldn't be possible to just rename the category without changing the permalink.

See gohugoio/hugo#11722
@hacdias
Copy link
Contributor Author

hacdias commented Feb 12, 2025

Hi! Is there a plan to address this? I just made a PR for it: #13382

@jmooring
Copy link
Member

@hacdias This issue is still a proposal (see labels). If the project lead accepts the proposal the label will change to "enhancement". At that point PRs will be welcome.

@bep bep added Enhancement and removed Proposal labels Feb 12, 2025
@bep bep modified the milestones: Unscheduled, v0.144.0 Feb 12, 2025
@bep bep added Proposal and removed Proposal labels Feb 12, 2025
@bep
Copy link
Member

bep commented Feb 12, 2025

  • Currently we have :filenameand :slugorfilename.
  • I don't see how :contentbasename and :contentbasenameorslug would/could replace the above.

Is this intentional or should it be switched? (:slugorcontentbasename)

@bep
Copy link
Member

bep commented Feb 13, 2025

OK, here is what I suggest we do.

This is the current logic in #13382:

// pageToPermalinkContentBaseName returns the URL-safe form of the content base name.
func (l PermalinkExpander) pageToPermalinkContentBaseName(p Page, _ string) (string, error) {
	if p.File() == nil {
		return "", nil
	}
	return l.urlize(p.File().ContentBaseName()), nil
}

// pageToPermalinkContentBaseNameOrSlug returns the URL-safe form of the content base name, or the slug.
func (l PermalinkExpander) pageToPermalinkContentBaseNameOrSlug(p Page, a string) (string, error) {
	name, err := l.pageToPermalinkContentBaseName(p, a)
	if err != nil {
		return "", nil
	}
	if name != "" {
		return name, nil
	}
	return l.pageToPermalinkSlugElseTitle(p, a)
}

I suggest that for :contentbasename:

  1. Try pageToPermalinkContentBaseName
  2. Fall back to pageToPermalinkSlugElseTitle

For :slugorcontentbasename (renamed):

  1. Try Slug()
  2. Try pageToPermalinkContentBaseName
  3. Try Title

This way we're 1) Mostly compatible with what we have and 2) People can have their slug win if set in front matter.

Agree? @jmooring @hacdias ?

@jmooring
Copy link
Member

Sorry for the delay. This sounds right to me, but I would like to take the PR for a spin to be sure.

@bep
Copy link
Member

bep commented Feb 14, 2025

@jmooring I just pushed and updated PR. I plan on doing a Hugo release Monday evening (Norway time).

@jmooring
Copy link
Member

This works great.

@hacdias
Copy link
Contributor Author

hacdias commented Feb 14, 2025

It sounds like a good idea to make it slugorcontentbasename instead. It's more useful.

bep added a commit to bep/hugo that referenced this issue Feb 15, 2025
* Make it work for all pages, including those created from content adapters and not backed by a file.
* Allow the `slug` to win, so the new tokens are:

`:contentbasename`:

1. ContentBaseName

`:slugorcontentbasename`:

1. Slug
2. ContentBaseName

Note that a page will always have a `ContentBaseName`, so no need to fall back to e.g. the title.

Closes gohugoio#11722
bep added a commit to bep/hugo that referenced this issue Feb 15, 2025
* Make it work for all pages, including those created from content adapters and not backed by a file.
* Allow the `slug` to win, so the new tokens are:

`:contentbasename`:

1. ContentBaseName

`:slugorcontentbasename`:

1. Slug
2. ContentBaseName

Note that a page will always have a `ContentBaseName`, so no need to fall back to e.g. the title.

Closes gohugoio#11722
bep added a commit to bep/hugo that referenced this issue Feb 15, 2025
* Make it work for all pages, including those created from content adapters and not backed by a file.
* Allow the `slug` to win, so the new tokens are:

`:contentbasename`:

1. ContentBaseName

`:slugorcontentbasename`:

1. Slug
2. ContentBaseName

Note that a page will always have a `ContentBaseName`, so no need to fall back to e.g. the title.

Closes gohugoio#11722
bep added a commit that referenced this issue Feb 17, 2025
* Make it work for all pages, including those created from content adapters and not backed by a file.
* Allow the `slug` to win, so the new tokens are:

`:contentbasename`:

1. ContentBaseName

`:slugorcontentbasename`:

1. Slug
2. ContentBaseName

Note that a page will always have a `ContentBaseName`, so no need to fall back to e.g. the title.

Closes #11722
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants