Adding Social Media Sharing Buttons to a Nikola Site
In November 2011 I migrated my site from Joomla to Nikola.
Unlike Joomla (and, for that matter, Wordpress/Drupal), Nikola is a static site generator (SSG): when adding content to the site I invoke Nikola and it generates a static files for each of the pages in the site (one of which you're reading now).
This provides significant security and performance benefit. There's no PHP in the background calculating what to serve to you, the file is simply loaded from disk and served on request, reducing both response time and attack surface.
However, because responses are not dynamically calculated, there are things that become harder as a page cannot dynamically include something based upon the user's request.
Social Media sharing icons are an example of this.
In a dynamic site, we might update a template to include
<div class="social-icon">
<?php
// Broken up for readability on smaller screens
$t = urlencode($page->title);
$p = urlencode($_SERVER['REQUEST_URI']);
$d = "https://www.bentasker.co.uk";
?>
<a href="https://twitter.com/share?text=<?php echo $t; ?>&url=<?php echo $d . $p; ?>&via=bentasker">
Tweet This
</a>
</div>
This injects the title of the current page, as well as the path of the page being requested (in practice you'd use one of the CMS's methods rather than the $_SERVER
superglobal, but it allows the example to fit into a small screen more easily).
In a SSG we need to use a slightly different approach. Although the underlying principle is similar, rather than acquiring details from the request, we instead need to ask Nikola's templating engine to include specific details from the post so that we can display preconfigured buttons like these:
This post details the process of adding social media sharing icons to Nikola post pages - it's more or less exactly the process I used to add icons to my own site.
Creating a Custom Theme
You might already have a custom theme (a template in Joomla speak), but as Nikola comes with a bunch of built in ones it's also quite possible that you haven't.
You can check the current theme in conf.py
grep "THEME =" conf.py
Then look in the themes
directory to see whether a directory exists with that name
ls themes
If not, create a new theme as a child of whichever theme is currently in use
nikola theme -n <new theme name> --parent <theme name> --engine mako
For example, when first setting up this site, I ran
nikola theme -n bootblog4-btasker --parent bootblog4 --engine mako
Nikola will then copy the base files into the new theme.
Enable the theme by editing conf.py
and setting THEME
to be the name of the theme created above.
THEME = "bootblog4-btasker"
Copying the Post Template in
Although there's a custom theme, it may not yet contain the post template because it's not added to custom themes by default, instead inheriting from the parent theme.
The following command will check whether the template exists and, if not, copy it into the theme (remember to provide your theme name)
if [[ ! -e themes/<new theme name>/templates/post.tmpl ]]
then
nikola theme -c post.tmpl
fi
You should now have the post.tmpl
template in your theme, ready for editing.
Button Types
There are two mechanisms which can be used for social media sharing buttons:
- Load javascript from each social network to create tweet/like/share buttons
- Use locally hosted images with a hyperlink
My preference has long been strongly towards the second option, because
- Buttons load faster
- A social media outage/issue doesn't block rendering of our site
- Visitor's privacy is preserved (sites really should avoid embedding active social media content to prevent networks tracking users around the web).
- Javascript isn't required for the buttons to function
- Compromise of the social media JS doesn't threaten the security of our visitors
However, using local images does require images to use in the first place.
At time of writing, some of the ones I use on my site are from a single source of freely available images:
The others are
- Twitter share button: created using the official logo before I found the site above
- The email button: built with an icon from that site (because they didn't have an explicit share one)
- The Telegram button: built from the official logo
- The QQ button: built from official logos
I saved my images into images/social-icons
:
ls -1 images/social-icons/
email.jpg
linkedin.jpg
qq.jpg
reddit.jpg
telegram.jpg
tweet_button.jpg
whatsapp.jpg
If you choose a different path (or filenames) remember to amend when we add markup to the template shortly.
If for some reason, you do want to use javascript embeds, the process for adding them is much the same as the one we'll follow for images (you'll just paste in the embed code rather than the markup that I provide).
Adding Social Icons
In order to add the icons/buttons we need to edit post.tmpl
(remember to substitute your theme name in).
vi themes/bootblog4-btasker/templates/post.tmpl
Find where in the template you want to add the icons. I opted for just after the </div>
following ${post.text()}
so that the icons would display at the end of the content:
First we create a div
to house the share buttons
<div class="socials">
</div>
Within that, we'll need to create an entry for each of the social media sites.
<a href="https://twitter.com/share?text=${post.title()|h}&url=${abs_link(post.permalink())}&via=bentasker"
target=_blank
rel="noopener nofollow"
>
<img class="twitterimg"
loading="lazy"
src="/images/social-icons/tweet_button.jpg"
alt="Share this post on Twitter"
title="Share this post on Twitter"
>
</a>
(Remember to change the value of via
in href
to be your Twitter username (you can remove it if you don't have a Twitter account), as well as the path in the image src
if necessary).
Within the URL we're calling three functions provided by the templating engine:
-
post.title()
: returns the title of the post (the|h
tells the engine to HTML encode it) -
post.permalink()
: returns the path to the post -
abs_link()
: converts the path from a relative to an absolute URL by bolting scheme and domain onto the front (those are taken from the config variableSITE_URL
).
This will result in output like the following
<a href="https://twitter.com/share?text=Adding%20Social%20Media%20Sharing%20Buttons%20to%20a%20Nikola%20Site&url=https://www.bentasker.co.uk/posts/blog/adding-sm-share-icons-to-a-nikola-site-template.html&via=bentasker"
target="_blank"
rel="noopener nofollow"
>
<img class="twitterimg"
loading="lazy"
src="../../images/social-icons/tweet_button.jpg"
alt="Share this post on Twitter"
title="Share this post on Twitter"
>
</a>
We use these template functions in the URL of each of the networks that we want to add a share button for:
<a href="https://www.reddit.com/submit?url=${abs_link(post.permalink())}&title=${post.title()|h}"
target=_blank
rel="noopener nofollow"
>
<img class="redditimg"
loading="lazy"
src="/images/social-icons/reddit.jpg"
alt="Share this post on Reddit"
title="Share this post on Reddit"
>
</a>
<a href="https://www.linkedin.com/shareArticle?url=${abs_link(post.permalink())}&source=www.bentasker.co.uk"
target=_blank
rel="noopener nofollow"
>
<img class="linkedinimg"
loading="lazy"
src="/images/social-icons/linkedin.jpg"
alt="Share this post on LinkedIN"
title="Share this post on LinkedIN"
>
</a>
<a href="https://api.whatsapp.com/send?text=${abs_link(post.permalink())}"
target=_blank
rel="noopener nofollow"
>
<img class="whatsappimg"
loading="lazy"
src="/images/social-icons/whatsapp.jpg"
alt="Share this post via Whatsapp"
title="Share this post via Whatsapp"
>
</a>
<a href="https://t.me/share/url?url=${abs_link(post.permalink())}&text=${post.title()|h}"
target=_blank
rel="noopener nofollow"
>
<img class="telegramimg"
loading="lazy"
src="/images/social-icons/telegram.jpg"
alt="Share this post via Telegram"
title="Share this post via Telegram"
>
</a>
<a href="https://connect.qq.com/widget/shareqq/index.html?url=${abs_link(post.permalink())}&title=${post.title()|h}"
target=_blank
rel="noopener nofollow"
>
<img class="qqimg"
loading="lazy"
src="/images/social-icons/qq.jpg"
alt="Share this post via QQ"
title="Share this post via QQ"
>
</a>
<a href="mailto:?subject=${post.title()|h}&body=${abs_link(post.permalink())}"
target=_blank
rel="noopener nofollow"
>
<img class="emailimg"
loading="lazy"
src="/images/social-icons/email.jpg"
alt="Share this post via Email"
title="Share this post via Email"
>
</a>
It is possible to do similar for Facebook, but you first need to create a developer account and acquire an Opengraph App ID. Once you've done that, you'll want the following URL format
https://www.facebook.com/dialog/feed?app_id=<your_app_id>&link=${abs_link(post.permalink())}
I've not included a full Facebook example here because I've not built one (actually, I thought quite hard about whether I even wanted to include Whatsapp).
Signal, unfortunately, doesn't appear to support an URL scheme for sending messages.
Once the markup is put together, we'll have added something like this to our template.
<div class="socials">
<a href="https://twitter.com/share?text=${post.title()|h}&url=${abs_link(post.permalink())}&via=bentasker" target=_blank rel="noopener nofollow">
<img class="twitterimg"
loading="lazy" src="/images/social-icons/tweet_button.jpg" alt="Share this post on Twitter" title="Share this post on Twitter">
</a>
<a href="https://www.reddit.com/submit?url=${abs_link(post.permalink())}&title=${post.title()|h}" target=_blank rel="noopener nofollow">
<img class="redditimg"
loading="lazy" src="/images/social-icons/reddit.jpg" alt="Share this post on Reddit" title="Share this post on Reddit">
</a>
<a href="https://www.linkedin.com/shareArticle?url=${abs_link(post.permalink())}&source=www.bentasker.co.uk" target=_blank rel="noopener nofollow">
<img class="linkedinimg"
loading="lazy" src="/images/social-icons/linkedin.jpg" alt="Share this post on LinkedIN" title="Share this post on LinkedIN">
</a>
<a href="https://api.whatsapp.com/send?text=${abs_link(post.permalink())}" target=_blank rel="noopener nofollow">
<img class="whatsappimg"
loading="lazy" src="/images/social-icons/whatsapp.jpg" alt="Share this post via Whatsapp" title="Share this post via Whatsapp">
</a>
<a href="https://t.me/share/url?url=${abs_link(post.permalink())}&text=${post.title()|h}"
target=_blank
rel="noopener nofollow"
>
<img class="telegramimg"
loading="lazy"
src="/images/social-icons/telegram.jpg"
alt="Share this post via Telegram"
title="Share this post via Telegram"
>
</a>
<a href="https://connect.qq.com/widget/shareqq/index.html?url=${abs_link(post.permalink())}&title=${post.title()|h}"
target=_blank
rel="noopener nofollow"
>
<img class="qqimg"
loading="lazy"
src="/images/social-icons/qq.jpg"
alt="Share this post via QQ"
title="Share this post via QQ"
>
</a>
<a href="mailto:?subject=${post.title()|h}&body=${abs_link(post.permalink())}" target=_blank rel="noopener nofollow">
<img class="emailimg"
loading="lazy" src="/images/social-icons/email.jpg" alt="Share this post via Email" title="Share this post via Email">
</a>
</div>
Supporting CSS
You'll almost certainly want to add some styling to control how the buttons are displayed. I opted to keep it simple:
.socials {
text-align: center;
}
.socials img {
max-width: 100px;
margin-right: 20px;
margin-bottom: 20px;
}
This can then be added into the theme's css
vi themes/bootblog4-btasker/assets/css/bootblog.css
Building The Site
Now that all our changes are in place, we just need to invoke Nikola in order to (re)build the site. Because there have been template changes it'll regenerate all pages
nikola build
Posts should now have social sharing icons, which when clicked should lead to a sharing dialog on the relevant social network
Conclusion
Adding social media sharing button to a Nikola based site is actually fairly straightforward once you know how, it's just that it relies on things which the handbook doesn't cover.
With relatively few steps, we've added social media sharing buttons to our site in a way that respects the privacy and security of visitors.
For those who want to get a little more advanced, information on theming is available, along with information on the variables and functions available in templates.