Create an Hexo Theme - Part 3: Comments, Analytics and Widgets

2016-03-11

In this multi part tutorial, you will learn how to create an Hexo Theme from scratch.

In Part 1 and Part 2, we have created all the pages of the blog. In this last section, we are going to add Disqus comments to our posts, implement Google Analytics and complete the sidebar’s widgets.

Disqus Comments

I have already written a blog post on how to implement Disqus comments in Hexo. Please refer to it if you need more information but here is how to do it:

The first step is to get a Disqus UID to test the comments, you can get it from your Disqus account here:

Disqus Unique Identifier

Then there are three things that need to be implemented, the theme config for disqus, the comments placeholder and the Disqus script. Let’s get going.

Theme config

We want the Disqus UID to be configurable, let’s add an entry to the theme’s _config.yml:

1
2
# Disqus Comments Shortname
disqus_shortname: klugjoTest

Comments placeholder

We are going to add comments to our page and post details pages. As always, let’s create a new partial view layout/_partial/comments.ejs and insert it at the end of our layout/_partial/article-full.ejs.

layout/_partial/comments.ejs
1
2
3
4
5
6
7
8
<div class="blog-post">

[...]

<!-- Comments -->
<%- partial('comments') %>

</div>

Disqus is exepecting a div#disqus_thread element, here is the official code from the documentation

1
2
3
<div id="disqus_thread">
<noscript>Please enable JavaScript to view the <a href="//disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>

Let’s integrate this into our comments partial:

layout/_partial/comments.ejs
1
2
3
4
5
6
7
8
<% if(page.comments && theme.disqus_shortname){ %>
<div class="blog-post-comments">
<h3>Comments:</h3>
<div id="disqus_thread">
<noscript>Please enable JavaScript to view the <a href="//disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>
</div>
<% } %>

First we are checking that comments are ON and that our disqus UID has been set. Then we are placing the Disqus markup code inside a container.

Here is the CSS code I have used for that container:

source/css/blog.css
1
2
3
.blog-post-comments {
margin-top: 50px;
}

Disqus script

Before we can test, we need to add the Disqus script which contains all the magic. Place it with all the other scripts at the end of layout/_partial/after-footer.ejs

layout/_partial/after-footer.ejs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- Disqus Comments -->
<% if (theme.disqus_shortname){ %>
<script type="text/javascript">
var disqus_shortname = '<%= theme.disqus_shortname %>';

(function(){
var dsq = document.createElement('script');
dsq.type = 'text/javascript';
dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/<% if (page.comments){ %>embed.js<% } else { %>count.js<% } %>';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>

<% } %>

The script is taken from the docs and the Disqus UID was parameterized.

Go ahead and test that everything is working as expected.

Google Analytics

Google Analytics implementation follows the same principle as Disqus so I will move through it quickly.

I have another blog post on that subject.

Setup the tracking ID in the theme’s config

Get your google analytics tracking ID from your account and add a new entry to the config.

1
2
# Google Analytics Tracking ID
google_analytics: UA-83746351-2

Create a new partial

Create a new partial view layout/_partial/google-analytic.ejs

layout/_partial/google-analytic.ejs
1
2
3
4
5
6
7
8
9
10
11
12
<% if (theme.google_analytics){ %>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', '<%= theme.google_analytics %>', 'auto');
ga('send', 'pageview');

</script>

<% } %>

This is a simple copy paste of Google Analytics Tracking code with a parameterized ID.

Integrate the partial

We want our tracking code on all pages, and there is not best place to put it on a page. Let’s add it at the end of our <head></head>:

layout/_partial/head.ejs
1
2
3
4
5
6
7
8
9
10
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">

[...]

<!-- Google Analytics -->
<%- partial('google-analytics') %>
</head>

And we are done !

Widgets

At the moment our widgets are just a bunch of hardcoded, static HTML inside sidebar.ejs. Let’s fix that.

Configuration

Let’s start with the configuration.

We are going to create two widgets, one About widget and one Tags widget. I want the JavaScript object version of the config to look like

1
2
3
4
5
6
{
widgets: {
about: "Here goes the about text",
tags: true // Or any additional configuration the widget needs
}
}

This is how it translates to YML inside our theme’s configuration file:

1
2
3
4
# Widgets List
widgets:
about: This blog is based off the official bootstrap blog template. Checkout the corresponding tutorial at <a href="http://www.codeblocq.com">http://www.codeblocq.com</a
tags: true

Our sidebar which is the placeholder of all our widgets, will need to iterate through all the widgets in the configuration and render them appropriately:

This what the sidebar EJS template now looks like:

layout/_partial/sidebar.ejs
1
2
3
<% for(var widget in theme.widgets){ %>
<%- partial('widget/' + widget) %>
<% }; %>

First Widget: About

Let’s build our first widget inside a new partial called layout/_partial/widget/about.ejs.

The code is copy pasted from the original bootstrap template and the text now comes from the configuration.

layout/_partial/widget/about.ejs
1
2
3
4
5
6
<% if(theme.widgets.about){ %>
<div class="sidebar-module sidebar-module-inset">
<h4>About</h4>
<p><%- theme.widgets.about %></p>
</div>
<% } %>

Second Widget: Tags

Let’s do something slighty more advanced for this widget. Display a paragraph with all the tags used in the blog, separated by whitespaces and with a font size proportional to the number of times the tag is used.

Here is the code in layout/_partial/widget/tags.ejs

layout/_partial/widget/tags.ejs
1
2
3
4
5
6
7
8
9
10
<% if (theme.widgets.tags && site.tags.length){ %>
<div class="sidebar-module">
<h4>Tags</h4>
<p>
<% site.tags.sort('name').each(function(item){ %>
<a href="<%- config.root %><%- item.path %>" style="font-size: <%- Math.min(item.posts.length * 2 + 13, 30) %>px"><%= item.name %></a>
<% }); %>
</p>
</div>
<% } %>
  • site.tags gives us access to all the tags
  • site.tags.sort('name') sorts all the tags by alphabetical order
  • item.path correspond to the relative URL to the archive page for that tag
  • item.posts.length gives you the number of time a tag is used
  • item.name is the Tag label

I chose 13 + (tag occurence * 2) in pixels (capped at 30px) for the font-size but feel free to use what you want.

The End

That’s the end of this tutorial, I hope you have learnt something interesting from it.

Here are a few things you can do if you want to develop it further:

Thanks for reading ! Really appreciate your comments, corrections, suggestions in the comments.