Customizing HUGO Webs

Following with the HUGO topic, there are many customizations that can be applied.

This can differ from theme to theme, but I want to consolidate here a few that found interesting and that I believe can be apply in any theme that you will choose (or maybe create?).

Tweaking HTML

How to include HTML content

Create /layouts/shortcodes folder on your HUGO folder.

Then create the file rawhtml.html with the following content:

<!-- raw html -->
{{.Inner}}

Then, you can use it in your posts by using the following logic:

Including Leaflet Map as HTML

For example, this output from leaflet map:


 


Custom URLs for Posts

Simply include the following parameter in the post configuration:

url: 'your-desired-path'

This will ignore the post-name.md from the file.

Add a render-link.html file which is processed (note to self: make sure you have a recent version of Hugo installed). This file is in /themes/your-theme-name/layouts/_default/_markup/ (or potentially somewhere directly too).

Editing the 404 Page

You will find it in your theme folder, under layouts/404.html.

{{- define "main" }}
<div class="not-found">404</div>
{{- end }}{{/* end main */ -}}

With some basic HTML knowledge you can edit that, for example to:

{{ define "main"}}
    <main id="main">
      <div>
       <h1 id="title"><a href="{{ "" | relURL }}">Take me back Home.</a></h1>
      </div>
    </main>
{{ end }}

Cover Image for your Posts

You can try with

Socialify

If your post content has ana ssociated Github repository, you can create an automatic cover for your post thanks to the fantastic work from https://socialify.git.ci/

Decide the parameters that you want to be visualized and generate the link that will be as the cover - image parameter in the post. Like this:

cover:
    image:
https://socialify.git.ci/JAlcocerT/R_Stocks?description=1&descriptionEditable=Shiny%20Dashboard%20that%20displays%20free%20available%20financial%20information.%20%0A%0A&font=Inter&name=1&owner=1&pattern=Solid&theme=Auto

Pretty handy for enhance the content related to our Github Repositories.

Add your Posts Tags

To the POST page

For that you will need to customize the file ’layouts/partials/post_meta.html’ of your theme:

{{- $scratch := newScratch }}

{{- if not .Date.IsZero -}}
{{- $scratch.Add "meta" (slice (printf "<span title='%s'>%s</span>" (.Date) (.Date | time.Format (default "January 2, 2006" site.Params.DateFormat)))) }}
{{- end }}

{{- if (.Param "ShowReadingTime") -}}
{{- $scratch.Add "meta" (slice (i18n "read_time" .ReadingTime | default (printf "%d min" .ReadingTime))) }}
{{- end }}

{{- if (.Param "ShowWordCount") -}}
{{- $scratch.Add "meta" (slice (i18n "words" .WordCount | default (printf "%d words" .WordCount))) }}
{{- end }}

{{- $author := (partial "author.html" .) }}
{{- $tags := (partial "tags.html" .) }}
{{- if $tags }}
    {{- $scratch.Add "meta" (slice $author $tags) -}}
{{- else}}
    {{- $scratch.Add "meta" (slice $author) -}}
{{- end}}

{{- with ($scratch.Get "meta") }}
{{- delimit . "&nbsp;·&nbsp;" -}}
{{- end -}}

Also, you have to create ’layouts/partials/tags.html’:

{{- $tags := .Params.tags -}}
{{- if $tags -}}
  {{- $lastIndex := sub (len $tags) 1 -}}
  {{- range $index, $tag := $tags -}}
    <a href="/tags/{{ $tag | urlize }}"> {{ $tag }}</a>
    {{- if ne $index $lastIndex }}&nbsp;·&nbsp;{{ end -}}
  {{- end -}}
{{- end -}}

This has been found thanks to an on going discussion of the PaperMod theme that I am using for the blog, but should be able to operate with other themes as well.

Add your HUGO POST Summary to Archive

Create the file (post_meta.html exists and it will affect what you see in /posts or /tags) themes/PaperMod/layouts/partials/post_meta_archives.html with the following (in the last part we make use of .Params.summary):

{{- $scratch := newScratch }}

{{- if not .Date.IsZero -}}
{{- $scratch.Add "meta" (slice (printf "<span title='%s'>%s</span>" (.Date) (.Date | time.Format (default "January 2, 2006" site.Params.DateFormat)))) }}
{{- end }}

{{- if (.Param "ShowReadingTime") -}}
{{- $scratch.Add "meta" (slice (i18n "read_time" .ReadingTime | default (printf "%d min" .ReadingTime))) }}
{{- end }}

{{- if (.Param "ShowWordCount") -}}
{{- $scratch.Add "meta" (slice (i18n "words" .WordCount | default (printf "%d words" .WordCount))) }}
{{- end }}

{{- $author := (partial "author.html" .) }}
{{- $tags := (partial "tags.html" .) }}
{{- if $tags }}
    {{- $scratch.Add "meta" (slice $author $tags) -}}
{{- else}}
    {{- $scratch.Add "meta" (slice $author) -}}
{{- end}}

{{- with ($scratch.Get "meta") }}
{{- delimit . "&nbsp;·&nbsp;" -}}
{{- end -}}

{{- if .Params.summary }}
  {{ with .Summary }}
    <div class="post-summary">{{ . }}</div>
  {{ end }}
{{- end }}

Modify the Looks

HUGO Main Page: adding pinned posts

In general, you’ll need to

  • Add the isPinned tag to the posts that you want to be kept in the main page
---
title: "My Pinned Post"
date: 2023-05-04T00:00:00+00:00
isPinned: true
#other_post_parameters
---
  • Modify the layouts/index.html. In my case, I am using PaperMod theme right now and I have the profile mode enabled.
    • When going to that index.html file, you will see that under that condition, it ‘redirects’ us to the file layouts/partials/index_profile.html. This is the file in charge of creating the main page of our blog.

Follow these steps:

  • Query the pinned posts in your config.yaml file. Add this code at the beginning of the HTML file (before the opening tag):
{{ $pinnedPosts := where site.RegularPages "Params.isPinned" true }}
  • Now we have the list of post that mets that condition ready, lets include them in our HUGO main page. To display the pinned posts in the profile widget. Add the following code right after the buttons div (before the closing tag of the profile_inner div):
{{- if $pinnedPosts }}
<div class="pinned-posts">
    <h2>Pinned Posts</h2>
    <ul>
        {{- range $pinnedPosts }}
        <li><a href="{{ .Permalink }}">{{ .Title }}</a></li>
        {{- end }}
    </ul>
</div>
{{- end }}

This block checks if there are any pinned posts, and if so, creates a div with the class pinned-posts, displays a header “Pinned Posts”, and generates an unordered list with links to the pinned posts.

Better summaries and post descriptions in HUGO

When writing a new post, be sure that you use the following variables:

description: "A great description for your post."
summary: 'A great summary that will appear in the posts view, instead of the automatic initial 70 words of your post.'

If you want to change the default 70 words of summary, use the following variable in the config.yml:

summaryLength: 100 #70

favicons

https://favicon.io/favicon-converter/

  • go to the theme folder
  • add a /static folder
  • add the files generated with the website

Use fonts

https://wowchemy.com/docs/getting-started/customization/

You can hide it by adding to the config.yml

params: hideFooter: false

If you want to customize it:

Modify the resulting .html in public

This is the file that will be in charge of creating the footer that will go to the /public folder when the web will be generated or that you will visualize locally:

  • better option: go to ``themes/your_theme/layouts/_default/partials/footer.html
    • and edit it accordingly

Add commenting systems to HUGO

Include at themes/your_hugo_theme/layouts/partials, the following comments.html

{{- /* You can add your own layouts/comments.html to override this file */ -}}

{{- $pageCommentSystems := .Param "pageCommentSystems"}}
{{- if not $pageCommentSystems }}
  {{- $pageCommentSystems = site.Params.defaultCommentSystems }}
{{- end }}

{{- $page := . -}}
{{- with site.Params.commentSystems -}}
  {{- if $pageCommentSystems.remark42 -}}
  {{- with .remark42 -}}
    {{- partial "remark42.html" (dict "page" $page "ctx" .) }}
  {{- end -}}
  {{- end -}}

  {{- if $pageCommentSystems.telegramWidget -}}
  {{- with .telegramWidget -}}
    {{- partial "telegram_widget.html" . }}
  {{- end -}}
  {{- end -}}

  {{- if $pageCommentSystems.disqus -}}
  {{- with .disqus -}}
    {{- partial "disqus.html" (dict "page" $page "ctx" .) }}
  {{- end -}}
  {{- end -}}
{{- end -}}

And also add the remark42.html

<div class="comments">
  <div class="title">
    <span>Comments</span>
    <span class="counter"><span class="remark42__counter" data-url="{{ .page.Permalink }}"></span></span>
  </div>
  <div id="remark42">
  </div>
</div>

<script>
  var remark_config = {
    host: '{{ .ctx.url }}',
    site_id: '{{ .ctx.site }}',
    components: ['embed', 'counter'],
    max_shown_comments: 20,
    theme: 'light',
    simple_view: true,
    admonition: JSON.stringify(['Please subscribe by email to receive reply notifications.']),
  };
  if (isDarkTheme()) {
    remark_config.theme = 'dark'
  }

  (function() {
    // toogle theme callback
    const key = 'remark42'
    if (!toggleThemeCallbacks.hasOwnProperty(key)) {
      toggleThemeCallbacks[key] = (isDark) => {
        const remark42 = window.REMARK42
        if (!remark42 || !document.querySelector('#remark42')) {
          return;
        }
        if (isDark) {
          remark42.changeTheme('light');
        } else {
          remark42.changeTheme('dark');
        }
      }
    }

    // init or reset remark42
    const remark42 = window.REMARK42
    if (remark42) {
      remark42.destroy()
      remark42.createInstance(remark_config)
    } else {
      for (const component of remark_config.components) {
        var d = document, s = d.createElement('script');
        s.src = `${remark_config.host}/web/${component}.mjs`;
        s.type = 'module';
        s.defer = true;
        // prevent the <script> from loading mutiple times by InstantClick
        s.setAttribute('data-no-instant', '')
        d.head.appendChild(s);
      }
    }
  })();
</script>

Dont forget to specify in your config.yml (as child in the params section):

params:
  commentSystems: #hugo papermodX
    remark42:
      url: https://remark42.fossengineer.com
      site: site_as_specified_in_remark_yaml
  defaultCommentSystems:
    remark42: true

FAQ

How to Modify the HUGO generated main page?

You have to modify the theme’s file: layouts/partials/index.html (in your theme it might be called differently - example in PaperMod it is index_profile.html when profile mode is activated).

You can add new features like listing some specific .md content under /content with:

        {{- if $Projects }}
        <div class="project-cards">
            <h2>Awesome F/OSS Projects</h2>
            <ul>
                {{- range $Projects }}
                <li>
                    <div class="project-item">
                        {{ if .Params.icon }}
                            <img src="{{ .Params.icon }}" alt="{{ .Title }} Icon" class="project-icon">
                        {{ end }}
                        <span class="project-title">{{ .Title }}</span> <!-- Project Title -->
                        <p class="project-description">{{ .Params.description }}</p> <!-- Project Description -->
                        <a href="{{ .Params.link }}">📖</a> <!-- Hyperlink to Project -->
                        {{ if .Params.Guide }}
                            <a href="{{ .Params.Guide }}">📋</a> <!-- Hyperlink to Guide -->
                        {{ end }}
                    </div>
                </li>
                {{- end }}
            </ul>   
        </div>
        {{- end }}

The related css will be normally at: assets/css/common/main.css, but again you might have different file affecting your theme, like in this case …/common/profile-mode.css

How to customize the css for HUGO?

Modifying Archive’s css

Under you theme folder, you should be able to find a similar structure and find the proper css file that affects the archive page: /theme/PaperMod/assets/css/common/archive.css

And in that file, include:

.post-summary {
    font-size: 10 px; /* 1.2rem; Adjust the font size*/
    color: var(--secondary); /*#c20c0c;  Adjust the font color */
    margin-top: 0.5rem;
  }

How to inject JS in ALL HUGO Posts?

Locate the single.html file in the theme’s layout directory (for example /theme/PaperMod/layouts/_default/single.html). Include the js before the end of the article:

</article>

{{- end }}
          {{/* end main */}}

Example: Adding Mailerlite to HUGO

</footer>

 <!-- MailerLite Subscription Form Container -->
<div class="ml-embedded" data-form="a-data-dorm"></div>

<!-- MailerLite Universal -->
<script>
    (function(w,d,e,u,f,l,n){w[f]=w[f]||function(){(w[f].q=w[f].q||[])
    .push(arguments);},l=d.createElement(e),l.async=1,l.src=u,
    n=d.getElementsByTagName(e)[0],n.parentNode.insertBefore(l,n);})
    (window,document,'script','https://assets.mailerlite.com/js/universal.js','ml');
    ml('account', 'an-account-id');
</script>
<!-- End MailerLite Universal -->

 {{- if (.Param "comments") }}
 {{- partial "comments.html" . }}
 {{- end }}
</article>

{{- end }}


         {{/* end main */}}

F/OSS Alternatives to MailerLite

Self-hosted newsletter and mailing list manager:

  • ListMonk
  • SendPortal

Other F/OSS Alternative Commenting Systems

https://gohugo.io/content-management/comments/

We have seen how to use Remark42, but there are other alternatives:

  • Cactus Comments (Open Source, Matrix appservice, Docker install)
  • Comentario (Open Source, self-hosted, Go/Angular, run locally, in Docker or Kubernetes)
  • Commento (Open Source, available as a service, local install, or docker image)
  • Isso (Self-hosted, Python)
  • Remark42 (Open source, Golang, Easy to run docker)
  • Staticman
  • Talkyard (Open source, & serverless hosting)
  • Utterances (Open source, GitHub comments widget built on GitHub issues)
  • Giscus (Open source, comments system powered by GitHub Discussions)