Block in a partial and defining in a page

FWIW, I assumed that I could cut up my baseof.html template into constituent files to organise them in a more granular way… Perhaps more granularly than many users tend to do. Here’s the structrure of my layouts/ folder:

layouts/
├── _default/
│   ├── baseof.html
│   ├── list.html
│   └── single.html
├── partials/
│   ├── _global/
│   │   ├── 0-head/
│   │   │   └── primary_head.html
│   │   ├── 1-body/
│   │   │   └── primary_body.html
│   │   ├── 2-header/
│   │   │   └── primary_header.html
│   │   ├── 3-main/
│   │   │   └── primary_main.html
│   │   └── 4-footer/
│   │       └── primary_footer.html
│   └── menus/
│       ├── basic/
│       │   ├── recursion-full.html
│       │   ├── recursion-none.html
│       │   └── sectional.html
│       ├── iconographic/
│       │   └── social-media.html
│       └── special-purpose/
│           └── a11y-jump-navigation.html
├── shortcodes/
└── 404.html

Several of the partials, in turn, reference partials that are “more deeply nested”.

To explain, here is the code in two of the files above:

layouts/_default/baseof.html

<!DOCTYPE html>
<html lang="en" class="w-full h-full">
{{- partial "_global/0-head/primary_head" . }}
{{- partial "_global/1-body/primary_body" . -}}
{{- partial "debug/json.html" (dict "siteParams" .Site.Params "currentContext" site.Menus) -}}
</html>

layouts/partials/_global/1-body/primary_body.html

<body class="w-full h-full">
<div class="w-full flex flex-col md:flex-row md:flex-wrap min-h-screen">
  {{- partial "menus/special-purpose/a11y-jump-navigation" . }}

  {{- partial "_global/2-header/primary_header" . }}
  {{- partial "_global/3-main/primary_main" . }}
  {{- partial "_global/4-footer/primary_footer" . }}
</div>
</body>

layouts/partials/_global/3-main/primary_main.html

{{- block "body-global-main" . }}
<main id="main" role="main" class="body-global-main">
  {{ .Content }}
</main>
{{ end -}}

What I’d been hoping to do was then define {{block "..."}} blocks in the various partials and then “redefine” ({{define "..."}}) them in page templates of greater specificity, only overriding/redefining blocks that were in need of “Section” specific changes.

I found this Discourse thread because, after having setup my code as displayed above, I began working on overriding the body-global-main block (initialised in primary_main.html as illustrated above) in layouts/_default/home.html… and it wasn’t working.

I can see now from @bep 's comment in this thread that the constructs {{block}} and {{define}} are “only meant to be used in baseof.html templates”. For anyone who was thinking of doing something like what I was trying, here’s the page to look up “baseof” (and other such) templates: Template lookup order .

It really would be great if we could cut up our baseof.html templates so that they are easier to parse through but, lacking that capability, for others who come across this thread, the way to go as of today is to:

  1. Keep ALL markup that you want to override using {{block}}/{{define}} constructs in a single file
  2. Then, simply accept that we’ll be duplicating the baseof.html at least a few (e.g., copy/paste in home.html which is what I need to do in my case) and then override in higher-specificity List/Single pages as needed.

The above doesn’t preclude a mix of cut-up of code like <head> and opening/closing <body> </body> tags into partial files. This should at least help keep things a bit cleaner. E.g. - snippets of what I’m doing now:

layouts/_default/baseof.html

<!DOCTYPE html>
<html lang="en" class="w-full h-full">
{{- partial "_global/0-head/baseof_head" . }}

layouts/_default/baseof.html

<!DOCTYPE html>
<html lang="en" class="w-full h-full">
{{- partial "_global/0-head/home_head" . }}

The above illustrates that I’ve moved removed the use of block ({{block "head-styles-global" . }}) in those two partials and thus, I’m able to better control and override which JS and CSS files are used globally (in {{partial "_global/0-head/baseof_head" . }}) by overriding the partial that is loaded in layouts/_default/home.html to be {{- partial "_global/0-head/home_head" . }} instead. To explain, the site’s home page will have vastly different styling and JS requirements and so, they shouldn’t be loaded with every page.

I do hope that maybe we can simply override {{block}} with {{define}} across “secondary” baseof templates in the future. I sorta wonder if maybe Hugo could provide this capability by defining hierarchical relationships between types of Template files like so:

  1. ROOT (any block defined here can be overridden in children): baseof.html (and variations thereof)
  2. Second-Tier: home, list, single, section, page ({{define}} blocks in these could then override {{block}} definitions in baseof.html. Templates of this tier can also define new blocks of their own.
  3. Third-Tier: content/TREE-STRUCTURE based specificity templates. E.g. content/pages and content/posts would both imply that they may have customised layouts in layouts/pages/[list|single].html and layouts/posts/[list|single].html. Third-Tier templates wouldn’t be able to define new {{block}} blocks, they’d only be able to override blocks defined in “lower level” tier templates.

I hope this info helps others in the future!

Related threads:

  1. Blocks and define override in hugo theme
  2. Support Base Templates and Blocks in partial rendering