Creating Redirects with Jekyll

13 years ago - #Jekyll#Ruby

One of my big hurdles in moving to Jekyll was making sure that people that stumbled across old URLs for my site would get to the new content. Creating redirects in Jekyll turned out to be a snap.

I had moved my site from Drupal. Their URL alias system is extensive (and cumbersome), and I really didn't want to lose all the good SEO I had on my old site. Google can take forever to crawl a dinky little site like mine – I'm not high on their list of priorities – so I was not looking forward to all those old URLs generating 404 errors. I made the redirect system part of my core requirements for a Jekyll relaunch.

There is some code based on redirects in the Drupal migrator, but it wasn't quite what I wanted. It creates multiple source files which live in your source folder forever. Considering that Drupal's URLs are quite messy, my source directory became unmanageable from all the junk directories and files that got created for the redirect files.

Instead of creating redirect files in the my source directory, what I wanted was to attribute redirect properties to a post. So a post would always have it's primary permalink URL, but it could also have multiple redirect URLs that lead the user back to the main permalink URL. That way, the redirect pages are created in the destination directory – not in the source directory.

Here's an example of what you would see in the YAML for a post that has redirects:

layout: post
title: Creating Redirects with Jekyll
redirects:
- /keiths/redirect/works
- /or-use-this-one

Next, I added a property to my _config.yml file to turn redirects on or off.

redirects: yes

Then I created a template in my _layouts directory called redirect.html. This is the file that is created for each redirect property of a post.

This page redirects a browser without any delay, but you could also create a page that instructs the user that the content has moved and to update their links. Note that the page.source_url code is the Jekyll permalink URL for the content. In other words, the place we want the user to end up.

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta http-equiv="refresh" content="0;url={{ page.source_url }}" />
</head>
</html>

And finally, I created the following file in my _plugins directory:

module Jekyll

  # The redirect page creates a simple page that refreshes a user from a URL alias to an existing post.
  # Redirects are only generated if there is a "redirects" parameter _config.yml

  class Redirects < Generator

    safe true
    priority :low

    # only process redirects if it's set in the config file
    def generate(site)    
      generate_redirects(site) if (site.config['redirects'])    
    end

    # find all posts with a redirect property and create a new page for each entry    
    def generate_redirects(site)
      site.posts.select{|x| x.data.key? 'redirects' }.each do |p|
        p.data['redirects'].each do |r| 
          redirect = RedirectPage.new(site, site.source, r, p.id)
          redirect.render(site.layouts, site.site_payload)
          redirect.write(site.dest)
          site.pages << redirect
        end     
      end
    end

  end

  # a class for generating the redirect pages.
  class RedirectPage < Page

    def initialize(site, base, path, destination)

      @site = site
      @base = base
      @dir  = path
      @name = 'index.html'
      self.process(@name)

      # Read the YAML data from the layout page.
      self.read_yaml(File.join(base, '_layouts'), 'redirect.html')
      self.data['source_url'] = destination

    end

  end

end

I think writing this code was the place where I truly fell in love with Jekyll. I thought about all the other systems I had worked on in which writing redirect functionality would have taken a lot longer. There would have been database migrations, programming front ends to accept multiple redirect values, and finally the redirect code itself. Implementing this in Jekyll was so damn clear and direct. It would have been my preference to handle the redirect with HTTP, but that's a small price to pay in my opinion.

blog comments powered by Disqus
This site is currently built on Jekyll. I had a few requirements in switching my site over, and one of the big ones was being able to break content out into categories. While the first part was pretty easy, there was no way to paginate posts in a category into multiple pages. Luckily, it wasn't hard to create a plug-in to fix that.
One of the features that I needed to add to Jekyll was the ability to easily group a collection of posts as a series. This entry describes how to add that functionality.