Huge problems with DRY because content files don't support any logic (like including small partials)

Original post was at https://github.com/spf13/hugo/issues/1212 but I was redirected here.

I find that Hugo is severely lacking and the current project architecture is just not that good for DRY. Let me explain:

All HTML pages are currently rendered based on content files. e.g content/features.html ~> example.com/features/ will exist. However, content does not support any logic and actually not even HTML officially (docs say that files in content should be in Markdown).

The docs also say that “most sites will only need a home page and the _default template”. I don’t find this to be true at all. In fact, I end up doing templates for almost EVERY page on my site and a corresponding content for that. This is because I want to create my pages’ contents from small partials too and not just have header, nav and footer come from the template.

Concrete example:

content/
  features.html
  pricing.html
  about.html

layouts/
  _default/
    single.html
  partials/
    ...lots of partials here...
  index.html
  • example.com/ is now easy to build by using logic and partials because index.html is a template and all the Go magic is at my disposal.
  • example.com/about/ is also easy because it just has some text that is added to the _default/single.html template from about.html.
  • example.com/features/ and example.com/pricing/ are a bit more complex pages and would otherwise fit inside the _default/single.html but I want to use Go logic to render things. Problem: content doesn’t support Go logic.

To overcome the problem with features and pricing I can change my structure to this:

content/
  features.html
  pricing.html
  about.html

layouts/
  _default/
    single.html
  features/
    single.html
  pricing/
    single.html
  partials/
    ...lots of partials here, used in index, about and pricing...
  index.html

However, the above is just stupid. Why would I want so many folders and files, especially when all my logic files have the same name: single.html ?


Another concrete example:

I have a _default/single.html that can support my blog posts. Excellent! However, my blog post structure is like this:

<lorem ipsum text here...> 

<banner with something, easy to include as a partial>

<lorem ipsum text continues here...>

The problem is that, again, I couldn’t do a blogpost.md that looks like:

lorem ipsum text here..

{{ partial "adbanner.html" . }}

lorem ipsum text here..

and I can’t do a template that looks like:

{{ .FirstHalfContent }}
{{ partial "adbanner.html" . }}
{{ .SecondHalfContent }}

So basically I would have to write the first half of the blog post to blogpost.md, the second half to blogpostsecondhalf.html to a partial and then do a template like:

{{ .Content }}
{{ partial "adbanner.html" . }}
{{ partial .Params.SecondHalfContent . }} <!-- the correct partial declared in FrontMatter -->

Umm… yeahh… I would much rather just import to partial within the file containing the blogpost.


Right now I notice that I end up doing a lot of content files that ONLY contain the frontmatter and a lot of textcontent and even HTML in the variables so I can do more multi-purpose templates and properly use partials.

Ideally, I’d probably enjoy a project where I could do easily use Go logic in all the files that get rendered into HTML pages. For example, inside the whatever-gets-injected-into {{ .Content }} in the following:

{{ partial "header.html" . }}
{{ partial "nav.html" . }}

{{ .Content }}

{{ partial "footer.html" . }}

Is it so that Hugo is only for blogs where almost every page looks the same? Should I be using Jekyll or something else instead ? Or am I missing something relevant here ?

Just because it’s not true for your site, doesn’t mean that statement isn’t true.

Without more information, it’s hard to tell, but this sounds like you are doing something very wrong. This isn’t normal.

This is how Hugo’s type system is organized. Most people find this organization is really powerful and easy to use. Perhaps you are misunderstanding Hugo’s type system or how the types relate to templates.

This isn’t Hugo. Hugo is the marriage of content with templates. I honestly don’t really understand your use case from what you’ve written here, but it sounds like you are doing something very out of the ordinary and likely incorrectly… Or you are just going about from the wrong approach.

You are welcome to try Jekyll. I think you will find it’s even more restrictive on what templates you can use. It’s also very blog specific, where Hugo is very general purpose. Liquid templates are more powerful than the templates Hugo supports, so maybe it’s what you need.

Not sure if it will solve all of your problems, but shortcodes will probably help.

are there some examples where hugo is being used in a website that is not just a blog ? One that has large pages with reusable partials and so on… I’d be very happy to look at the source of code of such an example.

Unfortunately I can’t show the current project I’m having these problems (not open source) :-/

Actually… these might be quite helpful indeed! This helps a lot with DRY in content files. Didn’t know about these yet.

spf13:

Hugo is awesome if I want to do this:

{{ partial “header.html” . }}
{{ .Content }}
{{ partial “footer.html” . }}

But what if the content itself is something that I want to make up of many pieces and not just one markdown file ? For example, what if the content is 1000+ lines of HTML and I want multi lang support ? Obviously I don’t want to do several html files with different languages as I would then be repeating the HTML (while changing the language of the text) and breaking DRY.

lotrfan mentioned shortcodes and these were definitely something I was looking for.

I totally understand the content <-> template relationship, however, there are a lot of cases when 1 template will only ever have 1 content file (or more if multi lang, 1 per lang). These cases kinda tend to create a lot of boilerplate because I need to make folder/single.html and then a matching content file for each of these.

I’m used to building HTML in a way that whenever there is any repeating structure, I want a loop + data to iterate over rather than copy paste. I want if-else logics, variables etc. The content part of template<->content is not giving me a chance to do that so I end up using a lot of templates that have a corresponding content file that is often empty (except for frontmatter).

The only problem with shortcodes, is that it only works in markdown .md files. If I understand it correctly, a post/page using .html does not get interpreted/parsed by Hugo. Thus you can only get the Go goodies when using .md.

Thinking out loud here… what if a “hybrid” .hugo file was used. Here’s a potential spec example:

---
title: "this is hybrid content"
date: "2012-04-06"
slug: "hybrid-post"
---

<hugo-content type="markdown">
My Hybrid Post
=====
* blah
* blah
</hugo-content>

{{ partial "adbanner.html" . }}

<hugo-content type="html">

<div>
    <h3>something else here</h3>
</div>

</hugo-content>

the <hugo-content> tags would be stripped out, but it’s a way for the parser to find and handle multiple different types and combinations of code & content.

That isn’t correct. You can (now) use shortcodes with .html in /content. Not sure when that was added – maybe it’s in the 0.15-DEV code base.

Where I can I find that in the code base? How does Hugo handle actually including Go Template code in <pre> or similar tags? Does it need to be escaped?

You can use shortcodes anywhere in the HTML files. No need to escape etc. Just try it. It works.

Both GitHub and this forum have search engines, try them.

One reference would be this:

And I see that this is in the 0-14 release.

I’m just getting into Hugo, but was also looking to have multiple “content areas” I could address directly in a template, rather than just one.

Instead of making multiple .md files, I’m finding (so far) that using multi-line indented blocks seems to work in the front matter.

For example a YAML .md file may have something like this:

---
title: "My Page"
description: "A very interesting bit of information"
date: "2015-11-11"
tags: ["awesomeness", "interesting"]

overviewinfo: 
     <div>
         <p>This page is awesome</p>
     </div>
     <div>
         <p>Did I say this page is awesome?</p>
         <p>I guess I did...</p>
     </div>


relatedinfo:
     <p>Also interesting:</p>
     <div>
         <p>This is one other <a href="otherpage.html">great page</a></p>
         <p>This is yet <a href="anotherpage.html">another great page</a></p>
     </div>


---
<p>Some my page content goes here...</p>
<div>Some more general content goes here...</div>

And in the template I can use each part independently:

{{ if isset .Params "overviewinfo" }}
<div id="overview">
    <h3 class="sectionTitle">Overview</h3>
    <div class="sectionContent">
    {{ .Params.overviewinfo | safeHTML}}
    </div>
</div>
{{ end }}

{{ if isset .Params "relatedinfo" }}
<div id="related">
    <h3 class="sectionTitle">Related Info</h3>
    <div class="sectionContent">
   {{ .Params.relatedinfo | safeHTML}}
    </div>
</div>
{{ end }}

<div id="general">
    <h3 class="sectionTitle">General Info</h3>
    <div class="sectionContent">
    {{ .Content }}

The problem I’m having is that the content in those other “front matter content” blocks can’t utilize shortcodes (and therefore references, etc), which would be handy outside of the main .Content block.

1 Like

@Murray_Thompson I’m curious as to why you’re putting so much markup in your YAML. YAML (ie, “YAML ain’t markup language”) is for data serialization, so moving these nested blocks into nested YAML key-value pairs is going makes more sense and will (hopefully) help your sanity in the long run.

You can read up more on the the spec at yaml.org. Also, taxonomies will eventually save your head from exploding if you continue to hard code your related pages HTML into the front matter.

I’m very new to Hugo, but between shortcodes, data files and data-driven content it seems like there’s quite a bit of scope for keeping things DRY, splitting things up and calling them where required.

3 Likes