Adding Netlify CMS and redirects to Hexo site, the missing pieces

Recently, I learned how to build and deploy my first Hexo site following A Step-by-Step Guide: Hexo on Netlify.

In order to create a better editorial experience and support internationalization, I added Netlify’s CMS and redirect rules to my site. You can find my project on JAMstack templates if you want to follow along. Now, sit back, grab a coffee and let me tell you what I discovered.

Russian doll your repos — .gitsubmodule

By default, Hexo generates boilerplate with a default theme called “Landscape”. It’s functional, it looks okay, but to be honest, it’s not what I want. It’s tempting to create a theme from scratch, but to quickly put together boilerplate with Netlify CMS and redirect rules, and to avoid maintenance worries, I decided to go with an existing one.

I found a popular theme called Material. I forked its Git repository and then added a .gitsubmodules file to the root folder of my site’s repo to include the theme as a sub-folder. If you’re not familiar with Git submodules, you can learn the basics by following along with this article: Git Submodules: Adding, Using, Removing, Updating. There are lots of resources available to help you learn more advanced tricks about Git submodules. Google around if you want to dive deep.

Add Netlify CMS to the site

Following the tutorial “Add Netlify CMS to Your Site”, I created an admin folder under my site’s source folder, which includes an index.html and a config.yml file.

Add Netlify Identity Widget

Netlify CMS works hand-in-hand with Netlify’s Identity service. To add it to my site, I needed to include the following script in the <head> of my CMS index page at /admin/index.html, as well as in the <head> of my site’s main index page.

<script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script>

Normally, front matter is where we store and access data of a post. Hexo allows us to introduce external data and reuse it in different places by storing data files under source/_data folder. It’s like a “mini database” that we store modularized data. Both YAML and JSON format are supported.

My goal was to rewrite the <head> of my site’s main index page with the external script tag.

I noticed that in the head.ejs file under themes/layout/partial folder, the following condition is included to allow the use of a custom <head>.

<!-- Custom Head -->
<% if (site.data.head) { %>
  <% for (var i in site.data.head) { %>
    <%- site.data.head[i] %>
  <% } %>
<% } %>

All that’s needed to do now is to store the Netlify Identity widget script inside a head.json/yml file and put it under the source/_data folder.

Tada! A Netlify Identity widget has been successfully added to the site. Now I can manage CMS admin users for my site without requiring them to have an account with my Git host or commit access on my repo.

Skip render folder and files

It turned out, there were some conflicts between the CSS of the theme and the Netlify CMS admin interface. I noticed that Hexo allows us to specify folders and files that shouldn’t be rendered by the Hexo engine by adding the path to skip_render rule in the root _config.yml file.

Here’s what I did. I added the following rule to tell Hexo not to render anything under the admin folder.

skip_render:
  - "*admin/*"

It worked! Now the admin interface is no longer overlapping the site home page.

This might not be necessary, depending on what kind of theme you use. It’s just something to tuck under your belt in case you bump into the same issue.

Internationalization and redirects

Sometimes site content needs to be available in different languages for members of the audience who do not read in English. We can certainly make a site more personalized by using Hexo’s internationalization/localization and Netlify’s redirect rules.

Multi-language support

First, make sure you have all the language files added to the language folder under the theme folder. Our example theme has it set up for us.

Secondly, change the language setting in the _config.yml file to specify the languages you want to present your site.

language:
  - [language_01]
  - [language_02]
  - [language_03]

By default, the i18n_dir is set to be :lang, which means that Hexo will detect the language within the first segment of URL. This plays well with our redirect rules that’ll soon be added.

Add redirect rules

Netlify’s GeoIP and language based redirects feature allows us to show targeted content according to geo location and browser preference. In our case, we’d like to show posts in our user’s preferred language.

You can add specific rules in a _redirects file under your root directory or add more structured rules in a netlify.toml file. The following examples are created in a _redirects file.

Example code of location based redirect rules:

/ /china 302 Country=cn,hk,tw

Example code of language based redirect rules:

/ /zh-cn 302 Language=zh

Now, if your users reside inside China, Hong Kong or Taiwan, they’ll be taken to https://yourwebsite.com/china when they type in the site URL. And if the language preference of their browser is set to be zh-cn, they’ll be taken to https://yourwebsite.com/zh-cn/. You can apply this technique for any other languages.

Feel free to do whatever you want with your folder structure. But make sure that the file paths in the redirect rules match your folder structure. E.g., I created a zh-cn folder for all the pages in Chinese and added an about folder with an about page:

source/
├── _data
│   └── head.json
├── _posts
│   ├── Platero
│   │   └── platero.jpg
│   ├── Platero.md
│   ├── hello-world.md
│   └── 你好.md
├── _redirects
├── admin
│   ├── config.yml
│   └── index.html
├── images
│   └── uploads
│       └── netlify-logo.png
└── zh-cn
├── about
│   └── index.md
└── index.md

You might have noticed that in my _redirects file, I specified /zh-cn/about as a redirect rule for the about page in simplified Chinese. So when somebody visits https://yourwebsite.com/about, they’ll be redirected to https://yourwebsite.com/zh-cn/about if their language preference is zh-cn.

Single language home page and archives page

Time to get a bit fancier. By default, our theme shows all the posts in all languages on the home page. That doesn’t look great when we apply our redirect rules and target content based on language preference.

Luckily, I found a plug-in called hexo-generator-index-i18n to solve the problem. It generates an index page for each language you have. And you can add configuration in your _config.yml file to show only one language on the index page.

Here’s how it works.

First you need to remove the existing plug-in in your package.json file:

"hexo-generator-index": "^0.2.0"

Then, install the new plug-in. And then you’ll need to add single_language_index under index_generator in your _config.yml file, and set the value to be true.

index_generator:
path: ''
per_page: 10
order_by: -date
single_language_index: true

Also, add :lang in permalink so that the post links match the redirect rules.

permalink: :lang/:year/:month/:day/:title/

Now, if you go to the home page again, you should be only seeing posts in one language.

Same applies to the archives directory. You can use the hexo-generator-multilingual-archive plug-in to localize archived posts, except that you don’t need to modify the _config.yml file.

That’s it. I hope this is helpful to you. Feel free to connect on twitter. I’d love to hear from you!