As the idea of a widget mechanism have been discussed here and there, as @bep suggested I am creating a specific thread. I will try to get this first post updated if the discussion should go on. The second post is intended a placeholder for technical issues / roadmap. @bep @spf13 : Don’t hesitate to edit.
To start on a good basis, I will discuss 1) What is a widget mechanism, 2) Why it can be a benefit for the hugo community, 3) How it would be used, and 4) How it might be developed.
What is a widget mechanism
A widget is intended as a block that can be put anywhere inside a website. In practice, this can be a menu, a list of the last posts, a call-to-action section, a sliding showcase, a social share block, a list of taxonomies, a search field, an inscription-to-newsletter field, a vcard, an arbitrary text block, or anything you can imagine as a separate block.
In a traditional Content Management System, a widget mechanism manages widgets: Where to put widgets (as widget areas), How to install them, and How to instance them. There are usually three main spots to have in mind:
- The widgets files are placed somewhere inside the website’s source tree (let’s say
widgets/
for instance). - A theme/template declares widget areas (something like
{{ widgets "sidebar" . }}
). - The end user defines widget areas inside the config file.
Benefits for the Hugo community
If we look closely at templating inside Hugo, we can see that Templates came before Themes. In some way, the theme’s mechanism is a structuration and normalization of the use of templates. We can see that it enables to easier share a website’s design.
The same analogy would be possible for partials and widgets. You can already create blocks as Partials. This is extraordinary! Now the lack of standardization leads to difficulties to share partials. For now, if we want to add a block inside a template/theme we always have to dive into the theme’s code and add a {{ partial "whatsoever.html" . }}
call.
This is precisely what we want to avoid. If a theme is built with customization in mind, we can do lots of things with a single configuration. See for instance what is possible inside the Hugo Multi Bootswatch theme. A lot of customization is possible.
But what to do if the theme has sidebars and footers, or other customizable place? I see two possibilities for that: 1) to put customizable content (as an arbitrary text field set by the end-user inside the config file – this is what @digitalcraftsman does in the excellent Hugo Material Docs), or 2) to set predefined empty partials places that can be manually set by the end-user (this is the use case that @spf13 chose for the main gohugo.io website: here you see that config file is very light, and here you see the partials included).
The blocks I told about inside the first section of this post are typically what an end-user wants to add on his pages. In my opinion, the theme should be agnostic on what specific blocks to display. The use case would be setting widget areas inside themes/templates, installing/creating widgets separately, and setting inside the conf file what widgets to inject inside the widget areas.
The theme’s creator freely sets the widget areas. But the cherry on the cake would be a recommendation about the areas namings. This enables themes to work “out of the box” and freely switch and test themes.
To sum up, if all this were implemented, we would gain:
- More generic themes, so better theme’s reusability out of the box for the community.
- More accessibility to non-developers. To create a website with the appropriate content, an end-user only has to install themes, install widgets, and edit the configuration file. This is more accessible than having to dive into templating and partials.
- The ability to create a centralized place to share widgets (just like the themes showcase).
- Maybe encouraging companies to create businesses onto Hugo, selling themes and templates (this is an other but related topic).
In my mind, Hugo would be the first static site generator (opportunity?). Combined with a theme inheritance (which is a totally different subject), this would bring more and more attractiveness.
Use case
Widget structure
A widget lives in a widgets/my-widget/
directory. It has to have at least two files: widgets/my-widget/README.md
(being a shareable object) and a widgets/my-widget/layouts/index.html
The could be a widget.yaml
config file if needed.
Theming/Templating
The theme/template declares widget areas as follows:
{{ widgets "sidebar-left" . }} {{/* Don't forget the dot. */}}
An isActiveWidgetArea
bool can be used to check if a widget area is active (if the end-user has really declared this widget area inside the config file).
First use case: putting default content
{{ if isActiveWidgetArea("sidebar-left") }} Put default widgets here {{end}}
Other use case: using default widget area names
{{ if isActiveWidgetArea("sidebar-left") }} {{ widgets "sidebar-left" . }}
{{ else if isActiveWidgetArea("sidebar") }} {{ widgets "sidebar" . }}
{{ else }} <!-- default widgets' code -->
{{end}}
Default widgets
Hugo should ship some core, widely-used, predefined widgets. In that way, the themes could put some default widgets to render better out of the box.
I am thinking of:
- Arbitrary text widget (eventually with options for raw html, markdown, templating)
- Navigation widget (menu)
- Last posts widget (list)
Widget areas and theming
- Theme developers would be encouraged to describe the widget area (at least their names) inside their README.md.
- Theme developers are free to choose the widget area names, but could be encouraged to use the following names:
header
,sidebar
,sidebar-left
,sidebar-right
,content-top
,content-bottom
,footer
,footer-left
,footer-center
, andfooter-right
. This enhance the ability to switch between themes (and therefore themes integration). - Theme developers could be encouraged to use condition to use some name for a sidebar if it exists, but a more generic name if not (see the Theming/Templating section).
End user: configuration file
The end user only has to install widgets and write things inside the config file. Below could be an example of what could embed the configuration file.
widgets:
sidebar:
- type: vcard
name: "King Arthur"
phone: (++123)456789
photo: "https://upload.wikimedia.org/wikipedia/commons/a/ad/Boys_King_Arthur_-_N._C._Wyeth_-_title_page.jpg"
- type: plain-text
content: "Website generated by **[Hugo static site generator](https://gohugo.io/ "Which is so beautiful")** on *{{ exec date }}*."
options: allow-html, allow-markdown, allow-exec # wink at issue https://github.com/spf13/hugo/issues/796
- type: list-categories
content-bottom:
- type: disqus
id: bstewiawzpoljzuisaei
post3-widgets: # included inside a post!
- type: showcase-bigflat
slides:
- title: "Meet us at the point"
text: Lorem ipsum dolor sit amet […]
picture: https://discuss.gohugo.io/uploads/gohugo/original/2X/3/3999949154d616b767f5984f74f89fb4cea50535.png
- title: "Hugo is so nice!"
text: Lorem 2 ipsum 3 dolor 4 sit amet 5 […]
picture: public/some-other-picture.jpg
Other questions to discuss
Who is declaring the html structure of the widget area?
- If this is done by Hugo this leads to normalization but rigidity (HTML5 vs XHTML vs other document language for example).
- If this is done by the theme, it implies more work for the developer (loops or description for a site-wide structure). The Hugo documentation could help to do that with pre-written and usable examples of widget areas.
- If this is done by the end-user this breaks the theme development process because the theme developer cannot style widget areas. Plus, this is less accessible.
IMO the Hugo could set a default behaviour (setting an <aside>
html5 block for widget areas and a <section>
block for widgets), which could be bypassed by the theme if necessary.
Widget template
Should it be widgets/my-widget/layouts/index.html
or some kind of widgets/my-widget/widget.html
?
See also
The related issue on Github: https://github.com/spf13/hugo/issues/2535
What do you think of all this? Do you think this functionality could be brought into Hugo? What would be the disadventages of such an approach? Do you think it could slow down Hugo?