I got a bee in my bonnet today about adding unobtrusive Twitter share links to this blog.
It involved the following steps:
- Finding out how to do it without using Twitter’s SDK on page
- Wiring that into a Hugo template
- Adding fragment to share links
- Adding mechanism for shortlinks on blog
Twitter Shares without their SDK
I prefer not to include Third Party JS on pages for security and purity reasons.
I searched around on NPM and found something simple that reflected this attitude: SocialMediaLinks and then built off of there for just the functionality I needed.
Wiring that into Hugo
I embed a few data attributes on .twitter_share
using a Hugo partial.
<a href="#"
target="_blank"
class="twitter-share in-headline"
data-url="{{.Permalink}}"
data-via="_ZPH"
data-title="{{.Title}}"
{{ if .IsPage }}
data-aliases="{{ .Aliases | jsonify }}"
{{ end }}
><i class="fa fa-2x fa-twitter"></i></a>
When the page loads, the div’s href is filled in using this fn:
document.addEventListener("DOMContentLoaded", function() {
_.each(document.querySelectorAll('.twitter-share'), function(el) {
const { via, title, aliases } = el.dataset
var ax, url
try {
ax = JSON.parse(aliases)
url = _.sortBy(ax, length)[0]
} catch (e) {
url = el.dataset.url
}
const href = SocialMediaLinks.create({account: 'twitter', url: url, title: title, via: via})
el.href = href
})
});
Parsing/Stringifying Urls
This is my happiest implementation of url parsing so far in Javascript.
The concept is adapted from https://gist.github.com/jlong/2428561 and adapted to suit ES6.
The clever trick is getting the browser to do the parsing by making it an a
element.
import * as _ from 'lodash'
export default class Link {
constructor(u) {
this.url = this.parseURL(u);
}
parseURL(url) {
// Credit: https://www.abeautifulsite.net/parsing-urls-in-javascript
// And Originally: https://gist.github.com/jlong/2428561
var parser = document.createElement('a')
// Let the browser do the work
parser.href = url;
// Available on parser
// protocol
// host
// hostname
// port
// pathname
// search aka queryParams
// hash
return parser;
}
getQueryParams() {
const kvs = this.url.search.replace(/^\?/, '').split('&');
return _.reduce(kvs, function(acc, kv) {
var k, v = kv.split('=');
if (_.isEmpty(k)) {
return acc
} else {
return acc[k] = v
}
}, {})
}
setQueryParam(k, obj) {
const qp = this.getQueryParams()
qp[k] = obj;
// Keep Parser in Sync so we can use href
this.url.search = this.queryParamsToString(qp)
return qp
}
emptyOr(v, ifEmpty, notEmpty) {
if (_.isEmpty(v)) {
return ifEmpty
} else {
return notEmpty
}
}
queryParamsToString(qp) {
return _.map(qp, function(v, k) {
return [k, v].join("=")
}).join("&")
}
toString() {
return this.url.href;
}
}
Adding fragment to share links
The ShareSocialMedia.create()
function appends a query param that’s a hashed value
so that retweets and content pathways can be tracked for analytics.
Short link redirects
When building the twitter link, we check for a shortcode in the Aliases portion of page metadata and fallback to using the full link. By using aliases frontmatter
for this Hugo will autogenerate redirect urls for each of these entries with a 301 link
The redirects work by generating an html document at that alias location like so (from the Hugo docs):
<html>
<head>
<link rel="canonical" href="http://mysite.tld/posts/my-original-url"/>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta http-equiv="refresh" content="0;url=http://mysite.tld/posts/my-original-url"/>
</head>
</html>
And Finally
My post-new script for creating new posts on blog has a function in it to take the filename of the post, md5 hash it, and take the first 6 chars. That value’s inserted into the page frontmatter.
Try it out ;-) aliased link