Jekyll博客中添加分类与多目录存放博客的方法

 
Category: Frontend

写在前面

最近发现一个问题, 博客数量越来越多了, 都放在_posts下实在是有点不方便, 于是想着分个类, Google 了一圈, 找到了一篇不错的博客, 如下:

Jekyll个人博客添加分类Category功能;

于是就跟着这个教程走了, 中途也发现一些问题, 因为我的 Jekyll 不是完全本地配置的, 还用了远程主题, 配置起来要兼顾原有主题.

博客结构

首先看一下我的原始目录:

.  zorchp.github.io
├── 404.html
├── categories.html
├── archive.html
├── index.html
├── about.html
+++++++++++++++++++++++++++++++
├── _config.yml
├── _data
│   ├── authors.yml
│   ├── licenses.yml
│   ├── locale.yml
│   ├── navigation.yml
│   └── variables.yml
+++++++++++++++++++++++++++++++
├── _drafts
│   └── xxx
├── _post
│   └── XXX
├── _includes
│   ├── article-footer.html
│   ├── article-info.html
│   └── head
+++++++++++++++++++++++++++++++
├── _sass
│   └── custom.scss
├── assets
│   ├── fonts
│   ├── images
│   ├── js
│   └── ...
└── README.md

上面就是一个基本的目录结构了, 简单介绍一下分割线分开的四个部分:

  • *.html 主页的HTML 文件, 例如404 是找不到内容时候显示的页面, index 是主页, archive 是归档页面, about是关于页面
  • *.yaml 配置信息, _config 是全局的配置文件, _data 里面的是导航栏(navigation), 基本变量(variables)等信息
  • *.html 博客的内容与博客页面的修改内容
  • *.css, *.js 样式与 js 代码, 媒体文件

然后就是要更改的内容了, 这里分为配置信息与 html 样式两个部分.

其中 _drafts 是草稿, 其实就是不会被渲染出来的页面(相当于在线博客的草稿箱了), 具体可参考 Jekyll 的文档.

基本配置

yaml 配置部分

_config.yaml

主配置

需要改的地方是:

# 之前是通过日期作子目录的方式, 注释掉
# permalink   : date
# 添加category内容
permalink: /:categories/:title/
  - titles:
        # @start locale config
        en      : &EN       Categories
        en-GB   : *EN
        en-US   : *EN
        en-CA   : *EN
        en-AU   : *EN
        zh-Hans : &ZH_HANS  分类
        zh      : *ZH_HANS
        zh-CN   : *ZH_HANS
        zh-SG   : *ZH_HANS
        zh-Hant : &ZH_HANT  分類
        zh-TW   : *ZH_HANT
        zh-HK   : *ZH_HANT
        # @end locale config
    url: categories/

加上上面这段. 添加导航栏部分的分类按钮.

注意 url 部分, 改成目录样式, 之前是 html 文件.

variables.yaml

default:
  text_skin: default
  highlight_theme: default
  lang: zh
  paths:
    root: /
    home: /
    archive:  /archive/

注意这个变量配置, 需要改一下, 之前是用文件来索引的, 现在要用目录来索引, 要不然会找不到归档页面.

html 页面的添加与修改

categories.html

新建这个文件, 注意 yaml 头的永久重定向链接, 需要写成

---
layout: page
permalink: /categories/
---


<div id="archives">
    {% for category in site.categories %}
    <div class="archive-group">
        {% capture category_name %}{{ category | first }}{% endcapture %}
        <div id="#{{ category_name | slugize }}"></div>
        <p></p>

        <h3 class="category-head">{{ category_name }} ({{
            site.categories[category_name].size() }})</h3>
        <a name="{{ category_name | slugize }}"></a>
        {%for post in site.categories[category_name] %}
        <article class="archive-item">
            <h4><a href="{{ site.baseurl }}{{ post.url }}">{{ post.title
                }}</a></h4>
        </article>
        {%endfor %}
    </div>
    {%endfor %}
</div>

_includes/article-info.html

这个文件是从 jekyll-TeXt-theme 这里拷贝来的, 需要改的部分在注释里面写了.

{%- assign _author = site.data.authors[include.article.author] | default: site.author -%}

{%- if include.html != false -%}

{%- include snippets/assign.html
target=site.data.variables.default.page.show_date
source0=layout.show_date source1=include.article.show_date -%}
{%- assign _show_date = __return -%}
{%- if _show_date and include.article.date -%}
{%- assign _show_date = true -%}
{%- else -%}
{%- assign _show_date = false -%}
{%- endif -%}

{%- include snippets/assign.html
target=site.data.variables.default.page.show_tags
source0=layout.show_tags source1=include.article.show_tags -%}
{%- assign _show_tags = __return -%}
{%- if _show_tags and include.article.tags[0] -%}
{%- assign _show_tags = true -%}
{%- else -%}
{%- assign _show_tags = false -%}
{%- endif -%}

<!--添加分类-->
{%if page.categories.size > 0 %}
<div class="blog-tags">
    Category:
    {%if post %}
    {%assign categories = post.categories %}
    {%else %}
    {%assign categories = page.categories %}
    {%endif %}
    {%for category in categories %}
    <a href="/categories/#{{category|slugize}}">{{category}}</a>
    {%unless forloop.last %}&nbsp;{% endunless %}
    {%endfor %}
</div>
{%endif %}
<!--添加分类-->
{%- assign _show_author = include.article.author -%}

{%- include snippets/assign.html target=site.data.variables.default.page.pageview
source0=layout.pageview source1=page.pageview -%}
{%- assign _pageview = __return -%}
{%- if _pageview or include.show_pageview -%}
{%- assign _pageview = true -%}
{%- else -%}
{%- assign _pageview = false -%}
{%- endif -%}

{%- assign _paths_archive = site.paths.archive | default: site.data.variables.default.paths.archive -%}

{%- if _show_tags or _show_author or _show_date or _pageview -%}
<div class="article__info clearfix">
    {%- if _show_tags -%}

    <ul class="left-col menu">
        {%- assign _tag_path = _paths_archive | append: '?tag=' -%}
        {%- include snippets/prepend-baseurl.html path=_tag_path -%}

        {%- for _tag in include.article.tags -%}
        {%- assign _tag_path = __return -%}
        {%- assign _tag_encode = _tag | strip | url_encode } -%}
        <li>
            <a class="button button--secondary button--pill button--sm"
               href="{{ _tag_path | append: _tag_encode | replace: '//', '/' }}">{{
                _tag }}</a>
        </li>
        {%- endfor -%}
    </ul>
    {%- endif -%}

    {%- if _show_author or _show_date or _pageview -%}
    <ul class="right-col menu">
        {%- if _show_author -%}
        <li><i class="fas fa-user"></i> <span>{{ _author.name }}</span></li>
        {%- endif -%}

        {%- if _show_date -%}
        <li>
            {%- include snippets/get-locale-string.html
            key='ARTICLE_DATE_FORMAT' -%}
            <i class="far fa-calendar-alt"></i> <span>{{ include.article.date | date: __return }}</span>
        </li>
        {%- endif -%}

        {%- if _pageview -%}
        {%- if site.pageview.provider -%}
        {%- include snippets/get-locale-string.html key='VIEWS' -%}
        {%- assign _locale_views = __return -%}
        <li><i class="far fa-eye"></i> <span class="js-pageview"
                                             data-page-key="{{ include.article.key }}">0</span>
            {{ _locale_views }}
        </li>
        {%- endif -%}
        {%- endif -%}
    </ul>
    {%- endif -%}

</div>
{%- endif -%}
{%- endif -%}


{%- if include.semantic != false -%}
{%- if _author -%}
<meta itemprop="author" content="{{ _author.name }}"/>
{%- endif -%}
{%- if include.article.date -%}
<meta itemprop="datePublished"
      content="{{ include.article.date | date_to_xmlschema }}">
{%- endif -%}
{%- if include.article.tags[0] -%}
{%- assign _keywords = include.article.tags | join: ',' %}
<meta itemprop="keywords" content="{{ _keywords }}">
{%- endif -%}
{%- endif -%}

主体部分

这里就是针对博客实际部分, 也就是 _posts 目录, 这时候可以先将之前的文件分成多个文件夹, 例如:

.
├── ASM
├── C_C++
├── DSA
├── Debug
├── English
├── Frontend
├── GUI
├── LaTeX
├── Linux-shell
├── Maths
├── Python
├── SQL-Database
├── UsefulTips
└── forJobs

下面以一个博客为例, 说一下添加的方法:

---
categories: [Debug]
tags: MacOS Debug Tips
---

其实就是添加了 categories: [Debug] 这部分而已..

一个技巧

之前文件很多, 那么如何批量修改(在文件的 yaml 头部分添加一行分类)呢?

首先要自己分类一下, 这个得自己来, 因为 tags 条目不尽相同.

然后就是我的思路了:

用万能的 Python!

import os
from glob import glob


def show():
    print(os.getcwd())
    fs = glob("*.md")
    for i in fs:
        with open(i, "a+") as f:
            f.seek(0)
            f.seek(4)
            # print(f.tell())
            content = f.read()
            f.seek(0)
            f.seek(4)
            f.truncate()
            f.write("categories: [Maths]")
            f.write("\n")
            f.write(content)
        print(i, "ok")


if __name__ == "__main__":
    show()

将这个文件放在需要批量操作的博客目录中: _posts/XXX 子目录

然后改一下 17 行的分类具体内容, 运行即可.

主要思路就是文件的偏移量, 然后追加写入即可, 这里需要注意, 即使使用文件尾追加的 a+ 模式, 并且修改了文件指针(使用 seek 系统调用), 还是只会在文件末尾添加行, 这就需要先保存文件的剩余内容, 然后截断文件(使用 truncate 系统调用), 最后补上即可.

这里还要注意一点, 就是如果你的文件没有 yaml 头(即用---开始的头), 并且文件的开始是中文(非 ASCII 字符), 那就会引起错误, 要解决这个问题, 只能先挑选出来出问题的文件, 这里可以用另一个 python 文件来做(Python 我滴神, 用 C++一晚上写不出来, 还是基础不牢).

def get_all_non_standard():
    fs = glob("./**/*.md", recursive=True) # 递归遍历所有文件
    # print(len(fs))
    for i in fs:
        with open(i, "r") as f:
            if f.readline() == "---\n":
                continue
            else:
                print(i)

这个简单的函数, 用来找所有存在 yaml 头的博客, 然后分别修改即可.

后记

重构之后的博客,可以看这里!