Jekyllで記事数付き親子カテゴリー一覧表示 - Qiita記事にまとめたものを見てみると、スムーズに順序よく実装できているように見える。きれいにまとめられているからか(自画自賛)。実際は土日を消化するほど時間がかかった。

親子カテゴリーでペアになるように配列を作ろうと決めるところまではすぐだったが、まずJekyllで配列を扱うのがピーキー過ぎて分からなかった。しばらく調べてLiquidで配列を作る、要素を追加する - Qiitaにもあるように配列を直接定義できなくて、文字列を切り分けるしかないと知った。

はじめはfor my_post in site.postsとしたらmy_post.categories[0]で親、my_post.categories[1]で子が手に入ることから、captureでなんとか変数にできそうだと思い(これも最初はassignでウンウン考えていた)、あとはポストによっては親子カテゴリーが両方もしくは片方被るのでどうやって選り分けるか。ifでがんばったらいけるか?とか……

あれこれ試すうちに、ひとまず状況を簡単にするため親子カテゴリーを両方もつことを前提とした。最初はカテゴリー1つのポストもあって、まあmy_post.categories[1]がなければnilになるからif区別できるか、と考えて気にしていなかったが、何も問題を複雑化することはない。

さらに紆余曲折あったが、どうにか1日使って以下のような実装までは完了した。細かい説明はしないが、親カテゴリーのみ記事数が表示されて、子カテゴリーは入れ子表示されるが記事数はまだ。

{% capture posts_name %}
  {% assign my_posts = site.posts | group_by: 'categories' %}
  |{% for my_post in my_posts %}{% assign post_name = my_post.name | remove: "[" | remove: "]" | remove: '"' %}{{ post_name }}{% unless forloop.last %}|{% endunless %}{% endfor %}
{% endcapture %}
{% assign integrated_categories_names = posts_name | split: "|" | sort %}
{% assign finished_categories = "nil, nil" | split: ", " %}

<ul class="taxonomy__index">
  {% for i in (1..categories_max) reversed %}
    {% for category in site.categories %}
      {% for integrated_categories_name in integrated_categories_names %}
        {% assign pair_categories = integrated_categories_name | split: ", " %}
        {% if pair_categories[0] == category[0] and category[1].size == i %}
          {% unless finished_categories contains pair_categories[0] %}
            {% unless forloop.first %}
              </li>
            {% endunless %}
            <li>
              <a href="#{{ category[0] | slugify }}">
                <strong>{{ category[0] }}</strong> <span class="taxonomy__count">{{ i }}</span>
              </a>
              {% assign finished_categories = finished_categories | concat: pair_categories %}
          {% endunless %}
          <ul class="taxonomy__subindex">
            <li>
              <a href="#{{ pair_categories[1] | slugify }}">
                <strong>{{ pair_categories[1] }}</strong>
              </a>
            </li>
          </ul>
        {% endif %}
      {% endfor %}
    {% endfor %}
  {% endfor %}
</ul>

ここまできたら終わりが見えた、と思ってからが本当の悪夢の始まりだったw

上記コード上から5行目まで、captureで変数を定義しているが、改行やインデントが含まれている。Qiita記事にはさらっと書いたが、これにハマッた。こう定義すると、posts_nameの先頭に何か生まれる。|{% for my ...と書いているが、これは先頭の|なしの場合にposts_nameを切り分けても[0]要素だけsortでアルファベット順整理の対象にならなかったためである。そこでひとまず先頭に空の配列を作ればsortできたことから余計な|をつけた。

最初のうちは、何か仕様上のバグか?と考えてひとまずこのまま子カテゴリーの記事数も表示させようとして、そうするとfor文をちょっと整理せなあかんな~と編集したら、謎の空白親カテゴリーを検出した。そのせいで空の親カテゴリー<li>タグができたり、あれこれ編集したら<ul class="taxonomy__index"></ul>がまず空タグとして出力されてその下に親子カテゴリー群ができてしまったりと、まったく意味が分からなかった。

上記のように余計な|をつけており[0]を出力させてみても何も見えないことから、どうやらposts_name先頭に存在するやつが諸悪の根源であるところまで突き止められたが、それが何か一向に分からず、消去もできなかった。stripで改行や空白が削除されるらしいがダメ、先頭0-6文字目にいる見えない何かをなんとか可視化しようとしたがダメ、見えないなりに変数に代入してremove削除も空振り、mapならと思ったが(これは使い方を間違えていたので)ダメ……あ゛ー!!

で、Jekyllテーマをコピーしているのでsortに成功しているcapture定義の変数のコーディングと見比べていたら、テーマの方はどうも読みづらい。captureが1行で書かれているからか~って思って、「ッッッ!!!」となった。いまのところ今年一番の驚きである。

そこからcapture定義を1行書きして、あれやこれやと実装しきれた。実装後にやっぱmapでもできるよな、と思って見直してみたらスルッとできた。上記コードをコミットしてから、実装完了コミットまで8時間半かかったw

でめたしでめたし