Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Create an Article Preview in Hugo

0.00/5 (No votes)
21 Nov 2019CPOL3 min read 2.5K  
Generate a thumbnail for your Hugo posts on the fly, then create a custom short code that uses thumbnails and page data like title and description to embed a post preview to interlink documents.

One of my favorite Medium features is the ability to link any site and embed a preview with a thumbnail, title, and summary. For example, pasting a link to my Durable Dungeon GitHub repo:

 JeremyLikness/DurableDungeon

Generates a preview like this:

Durable Dungeon Preview

Durable Dungeon Preview

I’ve since migrated to Hugo, so now what?

Hugo is extremely customizable and it is most likely possible to build the code to fetch a website and crawl metadata, but I decided to start with something a little more approachable and create previews for links internal to the blog. I know I can easily access the data through Hugo. The idea began when I implemented Google Search the first time. I noticed that some search results had thumbnails, but others didn’t. Upon researching this I discovered you can provide a thumbnail as metadata for a web page:

HTML
<meta name="thumbnail" content="thumbnail.jpg">

I always tag the main image for blog posts in my front matter using the image tag:

image: "/blog/myarticle/images/mainimage.jpg" 
images:
 - "/blog/myarticle/images/mainimage.jpg"
 - "/blog/myarticle/images/anotherimage.jpg"

Instead of pointing to a full-size image, I wanted to create a true thumbnail. I spent some time reading the docs for Hugo image processing and realized it wouldn’t be difficult at all. Hugo will process images inline and provide a link for the generated image. They are also placed in a resources folder, so they can be checked into source control and do not have to be regenerated each time.

⭐ Tip: Make sure you include your top-level resources folder in source control! I mistakenly included it my .gitignore and this was forcing Hugo to regenerate the images every time. Checking them in ensures they are only generated once and reused on subsequent passes. This makes the builds go faster and uses less storage.

The logic for my thumbnail generation looks like this, unrolled for visibility (in the template I have this in one line to save space in the generated content, but I also use the --minify option so that may be redundant). I removed redundant braces to make the logic easier to read but each statement is wrapped in double braces.

C++
if .Params.image
    $original := print "images/" (path.Base .Params.image)
    $originalImg := .Resources.GetMatch $original
    if $originalImg 
        $thumbnailImg := $originalImg.Resize "90x"
        printf `<meta name="thumbnail" content="%s">`
            $thumbnailImg.RelPermalink | safeHTML
    end
end

I first check that I’m on a page with image metadata. If so, I construct a path to the images based on how they are stored in the resources collection for the page. I parse the page resources for a match. If I get a match, I resize to 90 pixels wide, extract the link and print the meta tag.

After building this functionality I realized I could create a short code to do a similar thing with relative page links. I created a short code named relativelink.html:

C++
{{$page := .Site.GetPage (.Get 0)}}
<div class="container alert alert-secondary">
    <div><a href="{{$page.RelPermalink}}" alt="{{$page.Title}}">
        <strong>{{ $page.Title }}</strong>
    </a></div>
    <div class="float-left m-2">
    {{ if $page.Params.image }}
        {{ $original := print "images/" (path.Base $page.Params.image) }}
        {{ $originalImg := $page.Resources.GetMatch $original }}
        {{ if $originalImg }}
            {{ $thumbnailImg := $originalImg.Fit "200x100" }}
            {{ printf `<img src="%s" alt="%s">` 
                $thumbnailImg.RelPermalink $page.Title | safeHTML }}
        {{end}}
    {{end}}
    </div>
    <p><small>{{$page.Description}}</small></p>
    <div class="clearfix"></div>
</div>

The .Site.GetPage allows me to fetch a page based on its URL. I then extract the title, image, and description to create my preview. The thumbnail generation produces a slightly wider image and constrains the height as well. The result is that this short code:

{{<relativelink "/blog/migrate-from-medium-to-hugo" >}}

Generates this preview:

Migrate from Medium to Hugo

In June 2019 I migrated my blog from a Medium hosted solution to a self-hosted static website using Hugo. This post describes the steps of my journey including creating custom embeds, adding a Content Security Policy, and how I configured my Azure Storage Static Website and set up continuous deployment from GitHub to publish my blog.

This is a lot more interesting than a plain hyperlink and makes it easy for me to interlink blog posts.

What are your thoughts?

Regards,

Jeremy Likness

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)