GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS

Written by thoughtbot

External Posts In Jekyll

If you contribute to more than one blog, you may want to have all of your posts show up in a single stream, even if they aren’t hosted on that same site.

In my case, I like to have the “external posts” I write here for Giant Robots to show up on my personal blog, so that I can direct people to a single place to see everything I write. Having the posts all in one place also allows me to use Google Analytics to track clicks from my site to posts on Giant Robots.

At first glance, Jekyll doesn’t seem suited to this, but let’s dive in and see if we can make it work.

Meta Refresh

The first thing that comes to mind isn’t always the best, but let’s take a look at my original attempt.

The desire was to keep our Google Analytics page views by setting up a custom layout for external posts that will use a <meta> tag to redirect to the post externally after we get our pageview:

YAML front-matter in _posts/2013-07-12-external-posts-in-jekyll.md:

---
title: External Posts in Jekyll
layout: external
external_url: http://robots.thoughtbot.com/post/12345/external-posts-in-jekyll
---

_layouts/external.html:

<!DOCTYPE html>
<html>
  <head>
    <title>{{ page.title }}</title>

    <meta http-equiv="refresh" content="0;url={{ page.external_url }}">
  </head>
  <body><!-- Google Analytics JavaScript --></body>
</html>

This does the trick: We get Google Analytics to tell us that we had a page view, but the user is still redirected to the post externally before too long. Even with the 0 as the refresh delay, most browsers will load the entire page and render before redirecting, so unless we want to add an ugly “You are being redirected” message, we need a new solution.

Conditional when rendering site.posts

We already know whether a post is "external" to our site based on the external_url key in the front matter. Let’s see if we can use that knowledge when rendering the list of posts on our index.html.

{% for post in site.posts %}
  <dt><time>{{ post.date | date: "%d %b %Y" }}</time></dt>
  <dd>
    {% if post.external_url %}
      <a href="{{ post.external_url }}">{{ post.title }}</a>
    {% else %}
      <a href="{{ post.url }}">{{ post.title }}</a>
    {% endif %}
  </dd>
{% endfor %}

Okay, now we have posts rendering in our main post list, but if they have the external_url front-matter they will automatically link wherever the post was originally published. Sweet.

Unfortunately, there are a couple of downsides to this approach. First, we are probably confusing the user by linking them to an external post that looks just like the links within our site. Second, we have lost the ability to track page views.

Solutions

Fortunately, Jekyll has our back.

We can add another bit of front-matter to tell us what the actual site is that we're linking to. This allows us to style the links that will take the user away from the domain differently:

---
...
external_site: thoughtbot

We can take advantage of the onclick attribute to trick Google Analytics into thinking that by clicking on the link, we’re actually viewing that page:

<a href="{{ post.external_url }}" onclick="_gaq.push(['_trackPageview', '{{ post.url }}']);">{{ post.title }}</a>

We use post.url which actually comes out looking like /external-posts-in-jekyll since Google Analytics requires that page views be from a single site.

We could also achieve this without using onclick by setting a data attribute such as data-analytics-path and write JavaScript to find links with that attribute and add a click handler.

Bringing it all together

index.html:

{% for post in site.posts %}
  <dt><time>{{ post.date | date: "%d %b %y" }}</time></dt>
  {% if post.external_url %}
  <dd class="{{ post.external_site }}">
    <a href="{{ post.external_url }}" onclick="_gaq.push(['_trackpageview', '{{ post.url }}']);" >{{ post.title }}</a>
  </dd>
  {% else %}
  <dd><a href="{{ post.url }}">{{ post.title }}</a></dd>
  {% endif %}
{% endfor %}

style.css:

dl dd.thoughtbot:before {
  height: 26px;
  width: 27px;
  content: " ";
  background: url("ralph.png") no-repeat;
  background-size: cover;
  position: relative;
  display: inline-block;
  top: 4px;
  margin-right: 6px; }

front-matter:

---
title: External Posts in Jekyll
layout: post
external_url: http://robots.thoughtbot.com/post/12345/external-posts-in-jekyll
external_site: thoughtbot
---

If you'd like to see what this looks like in practice, all of this code was adapted from my implementation at http://calebthompson.io.