Add Page.Markup with scope support
Edit in 2024-08-16. I have revised my take on this after talking to @jmooring and thinking a little. The (original) primary motivation behind this PR (for me, anyway) was to make it possible to render different versions of a given page's content on, say, the home page. But we also want to make room for further improvements in this area without blowing the scope of this PR out of proportions. I have always wanted to create a map of the rendered content, but that would only be practical for Goldmark (and hard even there, I guess). I think that and similar extensions should be fairly simple to fit in the below.
- I have added
ContentWithoutSummary, which I know many have asked for - I have reduced the amount of name changes;
FuzzyWordCounthas been around for a decade and has become a brand by now. - The content Summary type will have a
Typediscriminator that is either "auto" or "manual" or "frontmatter" - For now, I suggest we keep all old content methods as aliases on
Page, e.g..Content,.WordCountetc.
With this you can do:
{{ with .Markup }}
{{ with .Render }}
{{ .Content }}
{{ .WordCount }} // ... etc.
{{ end }}
{{ end }}
You can also give it its own scope:
{{ range site.RegularPages | first 20 }}
{{ with .Markup "home" }}
{{ .Render.Content }}
{{ end }}
{{ end }}
type Markup interface {
Render(context.Context) (Content, error)
RenderString(ctx context.Context, args ...any) (template.HTML, error)
RenderShortcodes(context.Context) (template.HTML, error)
Fragments(context.Context) *tableofcontents.Fragments
}
type Content interface {
Content(context.Context) template.HTML
ContentWithoutSummary(context.Context) template.HTML
Summary(context.Context) Summary
Plain(context.Context) string
PlainWords(context.Context) []string
WordCount(context.Context) int
FuzzyWordCount(context.Context) int
ReadingTime(context.Context) int
Len(context.Context) int
}
type Summary struct {
Text template.HTML
Type string // "auto" or "manual".
Truncated bool
}
Fixes #8680
Looking at the above, I like most things about it; we greatly reduce the amount of methods on the giga Page interface (making it easier to understand, I think) and the introduction of "scoped" content rendering can solve many hard-to-workaround issues reported by users.
But I don't like the main name ...
{{ .Contents.Render }}
The above does not read well, and I think .Contents is confusingly too similar with what we had. So, instead of trying to find a term that describes what this is I thought we could find a term that describes what this is about, and also use the same term we use about this in the configuration:
{{ .Markup.Render }}
Or ...
{{ with .Markup }}
{{ .Render }}
{{ end }}
Which is what we do, we render the markup (Markdown, HTML, Pandoc ...) to one or more output formats.
Also, if we could somehow get the scope key above into the markup configuration, it would be useful for people to have some custom config for e.g. rendering of pages on the home page.
/cc @jmooring
I've tested this a bit. It works as expected except for ContentWithoutSummary which is expected at this point.
I did not play with the scope as described above because:
- I don't understand what it does
- I don't understand where I would want to use it
Both of these are documentation issues.
And while I appreciate grouping related items, I believe most users would prefer to do this:
{{ .Content }}
{{ .WordCount }}
Instead of this:
{{ .Markup.Render.Content }}
{{ .Markup.Render.WordCount }}
I also think the former is easier to understand.
So your intention to leave existing methods as-is makes sense to me.
@jmooring I have now pushed a version that passes all tests, including ContentWithoutSummary.
I don't understand what it does
So, scope is a little specialised, but questions related to this pops up on the forum (and here) from time to time. From the top of my head I can mention 2:
- There was one user asking how to render some post's
.Contentwith differenth2etc. levels on the home page. He tried passing down some.Store.Set "isHome" true, but that obviously doesn't work because of all the caching. (https://discourse.gohugo.io/t/render-headings-differently-on-home-page/51136/5?u=bep) - There was one user asking how he could hide all images when rendering content in RSS. I told him to add an empty render hook (or shortcode) template for RSS, which works, but is rather cumbersome ....
There are others and better examples, I'm sure, but those are recent ones.
So, when doing something like this in the home page template:
{{ range site.RegularPages | first 20 }}
{{ with .Markup "home" }}
{{ .Render.Content }}
{{ end }}
{{ end }}
The home page will get a fresh render of all of those 20 pages (home acts as a cache key); any shortcode/render hook template used doing that will have page.IsHome == true and hugo.MarkupScope == home.
There's a performance cost to the above, of course, so it should be ... used with care.
And while I appreciate grouping related items, I believe most users would prefer to do this:
I will keep these top level Page content methods for now, but at some point it may be a question about the cost of maintaining these in relation to what "users prefer". The motivation behind this grouping isn't primarily cosmetic.
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.