Hugo

Creating 'static' content that uses partials

Thank you for Hugo!
I am having a lot of trouble with this one. I will be using markdown for blog posts soon but for now am laying out the structure and design parts of my site and that relies heavily on HTML. When I put extensive and precise HTML into markdown files there are always little rendering issues so that approach is out. I’d really like to code straight HTML and be able to pull in all partial templates - just like I do on the homepage (index.html) - but for any page I need to.

The only way I can see to do this is by forcing the type and URL technique that’s been discussed, but that seems like a bit of a hack and seems messy. Is that the official way that Hugo wants us to do it or is there another solution?

Thank you again

That’s a fine way to do it given your constraints.

Steve Franciaspf13.com@spf13

I accomplish this by adding a ‘page’ parameter in the content’s front matter. Then whenever I render a single page I do a check if the page parameter is set, if so then I render it as a partial.

Within a piece of content’s front matter:

+++
page = "page/custom_page.html"
+++

Within the single.html page (belonging to the section you want to render):

 {{ if .Params.page }}
        {{ partial .Params.page . }}
 {{ else }}
 <!-- Render content normally -->
 {{ end }}

(Note, I don’t use with .Params.page because then the partial doesn’t work.(due to passing the environment through $.??)

This template will render the parial in layouts/partials/page/custom_page.html.
This partial can contain other partials or template code.

Anyways, I added this ability to render things that don’t really fit in a section or taxonomy(like “archive.md”, or content that can’t be rendered in a general way like Project. Project could be done generally but would be too complex with screenshots, features, feature thumbnails, links, etc. (I don’t think Hugo supports user-defined TOML tables? I may be wrong, haven’t tried it within the front matter yet.)

I’ll be announcing a project I’ve been working on soon, once I get some better documentation and tutorials setup around it.

3 Likes

Thanks for that suggestion.

I’m wondering whether this is a concern to others - basically, this still means we are creating what is essentially content and storing it under layouts - when it seems like as our websites grow it will be more elegant to store content in the content folder.

It is something that we need to find a "best practice " for and then decide if it is solved by code or convention

Here is a way I’ve found to address this issue. It relies on existing Hugo functionality, albeit some undocumented things.

1. Organize content in the content folder
Organize the content in your content folder the way you want it to be organized in your site. No need to override with URL in frontmatter. They key is remembering that a single file will turn into a folder as follows:

Content Folder:
photos.md
writing.md
writing/comedy.md
writing/history.md
writing/history/romanempire.md
writing/history/romanempire/vol1.md
family.md

Will produce this:
http://domain/photos/
http://domain/writing/
http://domain/writing/comedy/
http://domain/writing/history/
http://domain/writing/history/romanempire/
http://domain/writing/history/romanempire/vol1/
http://domain/family/

2. You can put complex HTML into the content pages, or just use Markdown, or a combination
Below the front matter (which I’ll get to in a second), you can put HTML if you want. There are still some issues with how a mardown file renders HTML. Comments sometimes get translated literally and sometimes a P tag is wrapped around the HTML when it shouldn’t be. I think these are known issues being addressed by Black Friday? But there are workarounds to this.

The easiest workaround if you want to use complex HTML is to simply rename the content file with an .html extension. This isn’t documented, but it works great. For these files, HUGO treats them exactly the same except Hugo won’t try to change any of the html inside.

3. Setup and use layouts to construct your final html pages
I had been stumped how to construct list layouts for sub-sections since Hugo by default only recognizes a top folder as a section. For example, how would you construct a layout summarizing all of the articles under writing/history? However, the easy answer seems to be to use frontmatter.
a) First, assign each content page a type. Start broad, because Hugo’s excellent abstraction abilities let you save being specific and narrow for when you need to be which is later. So start with setting type = “page” in content/writing/history.md (or content/writing/history.html). Then assign the content a layout, like layout = “page1”.
b) Then create a folder layouts/page and a layout at layouts/page/page1.html
c) The layout can look like this:

{{ partial “header1.html” . }}

{{ partial “headerNAV.html” . }} - in the header, you can use things like {{ .Title }} and {{ .Params.___ }} to pull out things specific to the piece of content that were set in the front matter.

{{ Here is where you put your Go and HTML code to list the pieces of content you want to list, likely filtering by a custom parameter you set in the front matter and access with .Params.parameter. For example, you can list just pieces of content having to do with history.}}

{{ partial “footer.html” . }}

OR Say you don’t need to list pieces of content. That is, on the http://domain/writing/history/ page, you just want to write something and show images, all marked up in a lot of HTML and javascript. All of that HTML stays in the content file as per above (at content/writing/history.html for example). The Javascript goes in the footer partial. And the rendering layout (layouts/page/page1.html) just looks like this:

{{ partial “header1.html” . }}
{{ partial “headerNAV.html” . }}
{{ .Content }}
{{ partial “footer.html” . }}

Remember: Keep things simple by using custom front matter parameters and accessing them in partials with .Params.____ so you don’t have to use a lot of layouts. Then when you need, create a new layout and set it in the front matter with layout = “newlayout”. Then when you have a lot of layouts, create a new type and a new type folder. Scale up in this order and you can have a complex site without too many layouts.

4. Addressing relative links
Most people here are probably much more experienced than I at HTML coding, but as I built out a site with many pages and subsections I stumbled on setting up links correctly. In case it’s needed, I found it easier to set the basehref in the frontmatter of a bunch of files and that way I only need a single header1.html partial that includes the following line:
<base href={{ .Params.basehref }}>
Just passing it along as another useful way to use Hugo’s variables and front matter.

19 Likes

+1

A best practice needs to be identified and included in the docs.

Having just tried this myself the simplest solution seems to be to put your markdown/html file in the root of the content directory, and to create a layout in layouts/_default/single.html. This did exactly what I would expect, which is to create a directory in /public with the name of my markdown file containing an index.html file.

I suppose you could add something to the front matter so you could filter these ‘static’ pages out when listing content from other sections.

If you need to get fancier in terms of layout on a page-by-page basis you can still do that.

2 Likes

What I expect was place a html in layout directory like home page.

.
..
layout/
  index.html
  about.html

So I gave it a try, but found Hugo didn’t render it.

No, and this is as documented. See http://gohugo.io/overview/introduction/

1 Like

On the intro page, Last revision: February 20, 2016, I do not see anything that explains this behavior.

I just pointed to “the documentation”, you would have to look it up yourself.

To sum up:

  1. Files in /layout are layout files, chosen by some rules by Hugo to render content. Putting static files in here is very unusual, and you should know the whats.
  2. HTML files in /static … is static, so what you put in the file is what gets published
  3. HTML files in /content:
    – if it has front matter (even only empty), it gets rendered as a content file with layout file, partials, shortcodes etc.
    – if it does not have front matter, it behaves as it was placed in /static
3 Likes

Can you please share your suggestions for multi language static landing pages? Right now I didn’t find an easy way to create a simple static html landing with easy supported translations. Example (which does not work now):

config.yaml
content/index.md
content/features.md
content/contact.md
i18n/en.yaml
i18n/ru.yaml
layouts/index.html
layouts/_default/single.html
layouts/partial/header.html
layouts/partial/footer.html

The problem here is that to make it work I need to create duplicates of content (index.ru.md, features.ru.md and contact.ru.md with complex html code which will be duplicated).
It also splits translations into different pieces (i18n folder + content folder) and makes translators job much harder (instead of translating one en.yaml file they need to copy/paste and translate every content file).

I suggest you put all the content into the i18n files and use the markdownify func to render the strings.

1 Like

But using your recommended approach I still need to create at least empty content/pagename.{language code}.md files.
And if I want to keep page titles translations in i18n/* files then I need to ignore the title in md file (probably, put a translation id there).

Yes, the world isn’t always perfect, but I don’t see the problem …?

For simple landing sites with every unique page (no similar “news” or “posts” content types) it’s much easier and convenient to have everything in one html page:

  • partials to include similar pieces of html
  • translation support (insert ids or default English text into the html and use translations from external i18n folder)
  • automatic generation of separate language pages (e.g. /en/page and /ru/page) if different translations are present in i18n (and used in the content source page, of course).

It will make hugo even more useful and easier for newbies.

I suppose it can be done relatively easy by having special extension for /content/ files, like /content/about.multilang or /content/about.html.

I suspect it would make Hugo into “some other product”, and I’m not sure about the “newbies” part. I think I understand what you’re talking about, but It is not on my list of things that I want to do in the near future, so any implementation/maintenance of such a feature will have to come from someone else.

There is another non-intuitive issue. If I create two content files:

content/test.md
content/test.ru.md

The following locations do not work:

layouts/test.html
layouts/test/index.html
layouts/test/single.html
layouts/_default/test.html
layouts/section/test.html

Hugo always uses template from _default/single.html. I suppose it would be intuitive to use layouts/test.html (like layouts/index.html).

Of course, the following works (but not very convenient):

content/test/index.md
content/test/index.ru.md
layouts/section/test.html

You have your intuition fixed strongly into your site model, which isn’t the main “Hugo use case”. There are no unambiguous cases on your list, i.e. no cases that, according to some other intuition, could be a section template, a taxonomy list template, …

Let’s summarize: hugo isn’t a convenient tool for simple multi-language landing web sites, because some additional and non-intuitive steps are necessary.