Using jekyll-paginate-v2
2019-12-18 00:00:00 -0600

A couple of weeks ago, I started the endeavor of adding Bootstrap to this website. You can read more about how this repository uses Bootstrap, and how to add Bootstrap to a static content site in my blog post Adding Bootstrap to Your Static Site.

But, soon after I started getting an upgrade in my CSS game, I realized that my pagination bar on my blog site was sorely outdated šŸ˜¢. At one point, I had the nerve to call this pagination bar beautiful:

But since completely revamping the whole looks of the site, this pagination bar was no longer acceptable. It was old fashioned, wouldnā€™t remember the page you were on if you navigated forward and back in your browser, and didnā€™t have pretty buttons. It was time for me to look into alternate pagination options.

I build and serve this site with GitHub Pages. GitHub Pagesā€™ built-in pagination suggestion is jekyll-paginate. But, it very clearly states that jekyll-paginate is no longer supported. The recommended newer version of Jekyll pagination is jekyll-paginate-v2.

I had considered jekyll-paginate-v2 before, and I briefly mentioned it in another blog post of mine. At that time, I didnā€™t want to make the necessary changes to my directory structure, and Iā€™d have to be willing to either add a trailing / to the end of my URLs, or Iā€™d have to be okay with some of my pages having that trailing /, and some not to, which I wasnā€™t okay with.

From a technical standpoint, it doesnā€™t really matter to the browser whether you write a / on the end of your URL or not; they resolve to the same host. Thereā€™s more detailed reasons why or why to have a trailing / on a URL, but the gist is that the / delineates a directory, which then would have files in it: https://example.com/directory/ and then https://example.com/directory/file.html šŸ¤·šŸ»ā€ā™€ļø.

In fact, my reading said that although having URLs without / is the newer, more popular thing, traditionalists would actually pretty much only have either the trailing / or the extension (the .html in the above example) in the URL. So if Iā€™m to follow these guidelines, then I probably should add the trailing / to the end of all of my URLs except the home page.

I could continue doing research, trying to decide what other pagination options to explore. But I figured that if I wanted to get anything easy done reasonably soon, Iā€™d have to just be okay with compromising on the trailing /.

So after admitting that Iā€™d need to accept the trailing /, I proceeded to set up jekyll-paginate-v2 on my repository. How hard could it be? šŸ˜†

I started by following the installation instructions. But, as youā€™ll understand later, I got only got through the second line in that section; I never finished reading that doc.

Instead, I jumped right into the work, copy-pasting the basics of the needed configuration into my config file, before realizing that although thereā€™s lots of documentation in this repo, they never quite clarify that your main Blog page needs to be in a ./blog/index.html file. Furthermore, they never actually say that your blog posts need to be in a _posts/ directory. Luckily, I poked around the examples enough to figure that out.

Thanks to this gist from @alialo on pagination, I was able to get the basic code of a simple pagination bar going right away. In fact, getting the main Blog page paginating wasnā€™t too hard at all!

But, I also wanted to make sure that I could paginate my sub-pagesā€”basically filtering my posts based on tag names and collection names. On my site, an example of a tag name is tech and an example of a collection name is Welcome to Kenya. The distinction between the two is that a blog post can have multiple tag names, and they should be one word long. But a blog post can only be a part of one collection, and the name can be multiple words with capitalization.

Filtering posts proved to be a little bit more complicated than just paginating all of the posts. The documentation for jekyll-paginate-v2 describes filtering based on what they call ā€œtagsā€ and ā€œcategories.ā€ So I started with a single tag, because I wasnā€™t quite sure yet how to deal with the collections. After I added the first bit of code to the tagā€™s filter, I realized that the documentation never properly mentioned in what directory I should put my filterā€™s file. I tried at least four different places I should put it. It wasnā€™t until my last idea when I realized that it had to be placed in the same blog/ directory as the index.html. But, as soon as I moved my tag file into the directory, so it looked like blog/tag.html, then it worked miraculously.

It was then easy to move all of the tags to have the same pattern. Moving to the ā€œcollection,ā€ I had more issues, mainly with 1) figuring out the best way to paginate the filtered pages, and 2) jekyll-paginate-v2 couldnā€™t be formatted to work with filtering a collection (only tags, categories, and locales, which is languages). So, I had to write my code as if my collection was a category instead. This meant changing several variable names, and in general renaming files and calls to have the word ā€œcategoryā€ instead of ā€œcollection.ā€ In fact, by the end of the night, I had changed almost every reference to a ā€œcollectionā€ in the whole codebase šŸ˜.

Despite all of this work, now every single tag and category filters blog posts properly. The last secret to getting pagination working on those pages is that I needed to save the URL of the filtered page: aka /blog/welcome-to-kenya or /blog/tech. And this way, we could append the page count number to the end of that: /blog/welcome-to-kenya/4/ or /blog/tech/2/.

After all of that work, I now have a pagination bar that makes me proud of this website. Just add in a few more pretty icons, and Iā€™m satisfied šŸ˜.


Haha! You thought the story was over, didnā€™t you? Wellā€¦ as soon as I merged in my pull request to add the new pagination, I realized something. That paragraph of the installation instructions that I didnā€™t finish? Well, the ending part of it warned that jekyll-paginate-v2 is not supported by GitHub Pages. This means that when somebody runs the code locally on their computer, they can use jekyll-paginate-v2 to their heartsā€™ content, and the site will load properly. But GitHubā€™s servers (which normally build the site for me), will not properly execute jekyll-paginate-v2, and thereā€™s no way to compile the pagination code properly without that.

If I had just finished that section, I couldā€™ve saved me a whole 30 minutes where the site wasnā€™t broken, and potentially even saved myself a little headache. But at this point, Iā€™ve come too far to turn back around and go back to my old-fashioned pagination. So, Google came to the rescue.

It turns out (surprise surprise) Iā€™m not the first person to run into this issue. Thereā€™s a whole discussion thatā€™s going on about this topic, and trying to integrate jekyll-paginate-v2 with GitHub Pages eventually, but it hasnā€™t made any progress lately. But, I did get some ideas from the discussion. Here are my options of how to proceed:

  1. After I finish making any changes to my site, I can commit my new source code to GitHub, bundle the project on my own computer, and then upload the bundled site to a separate branch in GitHub and have GitHub Pages deploy only that branch.
  2. I can switch to use the GitHub Pages supported jekyll-paginate and let GitHub Pages properly paginate my blog posts.

I started with the second approach. But after some more research, I learned that jekyll-paginate doesnā€™t allow for the filtering of tags and collections, which my site was heavily relying on. Therefore, to use jekyll-paginate would involve completely redoing my site, and several more hoursā€™ work.

Now, Iā€™m not a fan of needing my site to have to be built on a personā€™s computer to work properly. Itā€™s never a good idea to have a websiteā€™s deployment rely on a personā€™s physical computer (which could break, have compilation issues, or generally just not be available). But I figured that other people had run into this issue with jekyll-paginate-v2 and GitHub Pages, and Iā€™m sure somebody wrote a blog post about it (similarly to like Iā€™m doing now). So I looked up different ways to combat this issue.

What I found online suggests to go with the first approach, but donā€™t bundle the project on your machineā€¦ use a continuous deployment tool. And here comes Travis CI.

From Travis CIā€™s documentation,

Continuous Integration is the practice of merging in small code changes frequently - rather than merging in a large change at the end of a development cycle. The goal is to build healthier software by developing and testing in smaller increments. This is where Travis CI comes in.

As a continuous integration platform, Travis CI supports your development process by automatically building and testing code changes, providing immediate feedback on the success of the change. Travis CI can also automate other parts of your development process by managing deployments and notifications.

The ending part of that statement is important:

Travis CI canā€¦ [manage] deployments and notifications.

So, we could (in theory) make a change to the source code in GitHub, and then have Travis CI build my website and ā€œdeployā€ it to GitHub Pages. And, it turns out my site was already using Travis CI to test the Jekyll build process on every commit to the pages branch. So, I only had to add a few lines to have Travis CI also deploy my changes:

script:
  - JEKYLL_ENV=production bundle exec jekyll build --destination ./site

deploy:
  provider: pages
  local-dir: ./site
  target-branch: pages
  email: [email protected]
  name: Deployment Bot

The script section asks Travis CI to build the site to the site destination directory. The deploy section tells Travis CI to run a deploy to the GitHub Pages provider with the ./site directory, on the target branch pages, and which GitHub user to use (in this case, Deployment Bot with the email [email protected]). There are a few other little pieces to get it working properly, but you can check out my completed .travis.yml file if you want to see more. I did need to make a new branch in GitHubā€”the main branch. The idea here is that the main branch is used for me to store my source code for this site, and the pages branch is for GitHub Pages to deploy. Only the fully compiled and bundled site lives on the pages branch.

Itā€™s a little complicated, but, one deploy from Travis CI later, and the site was up and running again. AND I had the pagination option of my choosing that had all of the functionality I could ever want.

References


EDIT: Since writing this blog post, my website has switched to using CircleCI, and then to GitHub Actions, for all continuous integration tools. I wrote a blog post about why I switched to CircleCI, and wrote another post about why I again switched to GitHub Actions.