gohugoio / hugo

The world’s fastest framework for building websites.
https://gohugo.io
Apache License 2.0
75.9k stars 7.54k forks source link

Allow theme = ["base", "my-theme" ] (aka theme composition and inheritance) #4460

Closed bep closed 6 years ago

bep commented 6 years ago

I know this has been requested before, in the form of some extends = some-other-theme.

This isn't "theme inheritance" in its purest form (which would be "theme1 extends theme2 extends theme3"), more like theme composition. Which is much simpler to understand/implement, but with most of the added benefits.

This relates to my work on https://github.com/bep/html5up-to-hugo -- which, with the current Hugo, becomes less elegant than it could be.

The simple rule is that the themes' files will form a big overlay/union file system from left to right.

So:

theme = ["base", "my-theme" ]

What do you say?

maiki commented 6 years ago

I don't know how these themes relate to each other, it seems really complicated. I like what I thought was the basic flow of left to right inheritance.

theme = ["theme-made-for-project", "maiki-shortcode-collection", "that-one-override-for-the-gallery"]

In a CMS like Drupal or WordPress the themes have a direct "lineage", meaning they refer to a single theme as a "parent", though they can be chained along. Anything not fitting in that chain is added as a plugin.

I like that, it is easy to grok and easy to remember. And I already kinda build themes that way, except for using git to layer them on top of each other.

I wanted to point this use-case, but also to comment on the ordering: it should be consistent with the logic behind template inheritance. The default archetype comes to mind, where it makes sense that it isn't overridden, but it appears to be inconsistent with how other templates work.

I feel if the project/base theme is listed last it will be harder to remember and explain )as if it were easy to explain now! Ha!). :smile:

bep commented 6 years ago

it should be consistent with the logic behind template inheritance.

I think my last proposal is that. If we keep the archetype logic out of this (we really should), then the current order is 1. project 2. theme (i.e. from left to right).

Adding plural theme support you get 1. project 2. themes (and also potentially themes' themes if we go down that route). So, it is still left to right. Left will win on conflicts.

A single parent theme is probably easier to understand, but it gives away a ton of flexibility. I'm currently not a big theme user. But I see big needs in re-using and compose my project from components in a simple way (shortcodes etc.). This is the reason I spend time on this feature, any theme inheritance will be an added bonus.

I say that even a component with 1 shortcode is a theme. We could come up with some other name for that, but I suspect that would make this even harder to grasp.

bep commented 6 years ago

I cannot decide what is the best presedence order.

Given the theme list below:

theme = ["theme1", "theme2", "theme3"]

I have deliberately chosen very generic theme names, but you could imagine base-theme, my-shortcode-collection or whatever.

The question is: When two themes provide the same file (e.g. layouts/_default/single.html, who should win? Left or right?

regisphilibert commented 6 years ago

I did not expect that outcome :) Oh well.

kaushalmodi commented 6 years ago

@regisphilibert It would just feel so odd to write..

theme = ["debugprint", "my-shortcodes", "my-theme-overrides", "base-theme"]

But yeah, as long as this is well documented and understood, should be good.

bep commented 6 years ago

I did not expect that outcome :) Oh well.

My head was the other way around when I first thought about this, but revisiting it some months later, it just looked backwards... Reading from left makes project extends theme1 extends theme2 extends theme3 work as a sentence.

regisphilibert commented 6 years ago

Yes with the "extends" notion, it makes a lot of sense.

Here is a thought, I don't think it derails the issue, but stop me if it does.

Can we question the usage of the word "theme" for this config parameter? A theme is really something people take as a skin for their website. But now, it appears a lot of our themes will be something different. Like our already popular exemple of shortcode bundle, or output formats bundle.

I feel the word theme fails to encompass what this layout inheritance will really bring along. I think we need a word used as an umbrella for themes/plugins/addons/extension as it would make more sense in the long term.

bep commented 6 years ago

Can we question the usage of the word "theme" for this config parameter?

You may question it ...

I think it works if you think of a theme as a composite of components and other themes:

theme = ["component", "theme2", "another-component"]

Put all of those together and you got your theme.

Also, I don't want 2 terms for this, and changing it would be a fair amount of work, and you have to be really convincing to get me down that road.

regisphilibert commented 6 years ago

I think it works if you think a theme as a composite of components and other themes

Again put this way it makes more sense. This should be the way to put it in the doc when the time comes.

Thanks.

maiki commented 6 years ago

I've been thinking of it as everything is a set of one or more templates that operate on your content following a "theme". It could be visual layout, or shortcodes, or an output format, or all of those. So if we explain how we use "theme", it should be fairly straightforward.

I've read this conversation in a lot of projects over the years (naming and "theme"), and it is recurring issue that new users will likely know about themes solely via a PHP CMS. So they have to explain it a bit more. And we kinda have to explain everything a bit more with Hugo, it seems; a lot of folks don't quite grok the simplicity of a "template + content" workflow. ^_^

bep commented 6 years ago

Just a little heads up to people waiting for this: I'm very close to finishing implementing this now. To get this done, I had to refactor and get real control of all the theme related filesystem handling. With this issue closed, we will have a fully virtualized filesystem interaction without all the path logic sprinkled around.

And it seems to make Hugo faster, at least for sites with themes. The hugo docs builds about 15% faster on my MacBook.

ghost commented 6 years ago

https://github.com/gohugoio/hugo/issues/2639 cross-linking for reference

zxdawn2 commented 5 years ago

Is there any tutorial on how to use this function? I'm trying to use specific theme (hugo-resume) for 'about' page and common theme (AllinOne) for others. Will this function works for this situation?

I've tried this method to use two themes. But the structure is different and results in the wrong 'about' page.

regisphilibert commented 5 years ago
theme:
  - hugo-resume
  - allinone

The first homonymous template/data/i18n match will overwrite the later.

github-actions[bot] commented 2 years ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.