Adding Likes to Hugo site
Hey 👋, inspired by Brent Roose’s blog I decided to add a like button to all my posts in this blog. It’s a static site generated by Hugo since 2018.
It’s a nice little project that involved:
- Learning how to extend Hugo (and the template I am using) in the least disruptive way.
- Do some vanilla JS.
- Craft some very basic API that I can use to kickstart
api.aaron.com.es
(separate article is in the oven 🍞!).
Integrating with Hugo
Let me start by saying that it was a bit difficult to decide where to add this feature. Hugo allows for multiple ways: overriding sections, shortcodes, …
First I started by implementing it as a shortcode, but when I was almost done I realised that this would require
me to include in all the posts the {{< whatever_shortcode >}}
shortcode, which I didn’t want to.
After that I tried to override the layouts/_default/single.html
but when I was almost decided I checked the theme
and there were some “partials” like the footer.
Tested the partials approach, but I didn’t like the result because I wanted my like button to be right after the
post content.
So I went back to the layouts/_default/single.html
idea.
The process was very easy:
- Copy-pasted theme’s original layout with a command like this:
cp themes/manis/layouts/_default/single.html layouts/_default/single.html
. - Edited the file to include a new partial in the correct place:
{{ partial "likes" }}
. - Created the partial at
layouts/partials/likes.html
.
The frontend part
The frontend code is very simple. I separated HTML, CSS and JS in three different files.
layouts/partials/likes.html
<script type="text/javascript" src="/js/likes.js"></script>
<link rel="stylesheet" type="text/css" href="/css/likes.css">
<div class="likes">
<div class="likes__button">
<div class="likes__emoji">👍</div>
</div>
</div>
static/css/likes.css
.likes {
display: flex;
justify-content: center;
margin: 25px 0px;
}
.likes__button {
display: flex;
border-radius: 5px;
border: 2px solid #ff8181;
height: 50px;
align-items: center;
justify-content: center;
padding: 5px;
min-width: 50px;
}
.likes__button:hover {
background-color: #ff8181;
cursor: pointer;
}
.likes__emoji {
font-size: 25px;
}
static/js/likes.js
const sendLike = async () => {
// Get current page url.
const url = window.location.href;
// Send like to the API.
const result = await fetch(
"https://api.aaron.com.es/likes?url=" + encodeURIComponent(url),
{ method: "POST" }
);
// Return number of likes.
const data = await result.json();
return data.likes;
};
// Hook the click handler when DOM is ready.
addEventListener("DOMContentLoaded", () => {
const element = document.querySelector(".likes__button");
if (element) {
element.addEventListener("click", async () => {
const likes = await sendLike();
element.querySelector(".likes__emoji").innerHTML = `${likes} 👍`;
}, { once: true } );
}
});
Everything is ready in the frontend part! 🎉 What about the backend?
The likes API (backend)
I have to admit I got a little excited and overcomplicated (only slightly) the backend part. But it was for a reason, I plan on having this backend for other future projects.
The actual API is very basic. Only a couple of endpoints:
GET /likes?url={the-url}
: Will return a JSON containing the number of likes.POST /likes?url={the-url}
: Will increase the counter of likes for the given URL by one and also return the number of likes.
I will go in more depth regarding the implementation in an upcoming article! Stay tunned!
Result
Here you have it. Smash the like button! 👍👍👍
PS: Don’t be evil! Right now the API is missing any checks, so you can like the same post many times. I will fix that in the future.