Is it an anti pattern to create a hooks system in a Hugo theme?

I want to create a custom hooks system like WP from partials in different parts of my reusable theme, instead of copying files from theme to root for every site and making edits there. Is that an anti-pattern?

{{- if templates.Exists "_partials/hooks/before-head.html" }}
    {{- partial "hooks/before-head.html" . }}
{{- end }}

Then I could just create such a partial at the root to hook into the theme.

In my opinion not. And I have created an extremely overenginered such system myself :wink:

The main idea is that you could “plug in” whatever you want at specific points. If the user wants to use a Github discussions based comment system, or a DISQUS based one, let them do that. Look for a discussion hook and let it have the post data. If the user wants an Ad between post 1 and 2 - hook it in. Add a hook for analytics scripts in the header, add a hook for stuff in the footer.

You give your users the option to extend your theme without overriding the theme on updates. As long as you keep the hooks existing and/or find a way to anounce anything missing or wrong configured on CLI.

In my case I have a couple of modules that do stuff in the head tags of a website. The hooks look if these modules are there and plugs the tags in.

If you look at it from the WP point of view, you can even do filters. Hand something over to the partial and let it return the parsed content.

Example again: German language :wink: I sometimes filter text through a umlaut-filter. Or you have a tagline/subheading and want it to generate some random text. Send the text to a filter-partial and use what it returns in a variable.

Long story short: anti pattern? probably not. potential for excessive OCD traps? totally.

1 Like

The docsy theme uses this pattern extensively. I don’t know if it’s an antipattern, but I kinda like it.

1 Like

I think this is a good solution when needed.

You can also put an empty version of “_partials/hooks/before-head.html” in your theme. That way you can skip the templates.Exists check.

2 Likes

Another design pattern would be to use blocks:

inside the blocks you could implement whatever you need, calling partials, conditionals…

  • baseof.html
    This one defines two blocks you can define in the other templates:

    • before-head is empty by default but other templates may add that block
    • after-head has defined content but that can be overridden.
    <head>
      {{- block "before-head" . }}{{- end }}
      {{ partial "head.html" . }}
      {{- block "after-head" . }}
        {{- warnf "%s : after-head from BASEOF" .Path }}
      {{- end }}
    </head>
    
  • home.html
    only defines main → only after-head will be executed

    {{ define "main" }}
      {{/* main content */}}
    {{ end }}
    
  • page.html
    defines main and before-head → both are printed:

    • `before-head as defined in page.html
    • `after head as defined in baseof.html (default)
    {{- define "before-head" }}
      {{ warnf "%s : before-head from %s" .Path   templates.Current.Name}}
    {{- end }}
    {{ define "main" }}
      {{/* main content */}}
    {{ end }}
    

You can also:

  • change the content of after-head by defining that block in a page__section …
    {{- define "after-head" }}
      {{ warnf "%s : after-head from %s" .Path templates.Current.Name}}
    {{- end }}
    
  • remove after-head by explicit setting it to an empty action
    {{- define "after-head" }}
      {{/**/}
    {{- end }}
    

and - it’s imho not an anti pattern - but DRY to not copy 1 100 line template for just a one line change:

  • you have the code under control
  • don’t escalate usage :wink:

other options would be just conditional statements based on site or page config …

2 Likes

Hello @kijana!

If it can help you, we also use a hook system with empty files as @frjo suggested. It’s a great option to handle theme customisation. As our theme evolves, we add several hooks. To avoid a huge number of files in one common folder _partials/hooks, we managed to create a better file tree. We put hooks where they belong, for example: _partials/footer/hooks/before-end.html.

1 Like

I wanted to avoid creating those empty templates. So, to stop Hugo throwing an error, I added the if check. I document which hooks I need or created.

I like that approach. For now, my base theme is intended to just be overridden site wide, think like a script at the footer or a comment system before footer.

I like the approach. I don’t have a lot of hooks for now (just-5). I use descriptive names to let me know which is which. But I will take that into consideration.

Thank you everyone for your comments. I used the GeneratePress theme in WP before SSGs and I used their hooks system a lot. That inspired my current theme, which I am re-using for a few personal sites.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.