Pageのレイアウトの順番を操作可能にした

どういう問題が発生したの?


gray_back


プライバシーポリシーの場所がタグ一覧とカテゴリ一覧の間に挟まって、見た目があんまりよろしくない。
デフォルトではPageの順番はtitleの名前順?になっているせいでこんなことになっている。  

これを下の画像のようにしたい


gray_back


どうやって解決したの?

まず、Pageの中でも順番を指定したいPageにおいて、変数orderを作成する。

Title: プライバシーポリシー
Order: -99
...

Title: 管理者情報
Order: -1
...

そして、themebase.htmlの以下の部分がPageのレイアウトを決めている部分。

{% if DISPLAY_PAGES_ON_MENU %}
    {% for p in pages %}
        <li{% if p == page %} class="active"{% endif %}><a href="{{ SITEURL }}/{{ p.url }}">{{ p.title }}</a></li>
    {% endfor %}
{% else %}

これを以下のように変更した。

{% if DISPLAY_PAGES_ON_MENU %}
    {% for p in pages | selectattr('order', 'undefined') %}
        <li{% if p == page %} class="active"{% endif %}><a href="{{ SITEURL }}/{{ p.url }}">{{ p.title }}</a></li>
    {% endfor %}
    {% for p in pages | selectattr('order', 'defined') | sort(attribute='order') %}
        <li{% if p == page %} class="active"{% endif %}><a href="{{ SITEURL }}/{{ p.url }}">{{ p.title }}</a></li>
    {% endfor %}
{% else %}

これで、orderが定義されていないPageは先頭でtitleの順番で表示され、定義されているPageorderの値に従って表示されるようになる。

詳しく説明

まず、設定したorder等の変数はPageに辞書みたいな感じで定義される。
pagesPageのリストである。

ここで|の意味であるが、これはフィルターというらしく、まぁシェルのパイプラインと同義みたいなやつである。
pagesの一要素ごとにフィルターでselectattrを用いてorderが定義されているかを調べる。
定義されていないもの(undefined)は最初のfor文で表示し、定義されているもの(defined)は2つ目のfor文で表示する。
ここで、定義されている物では、そのorderの値に従ってソートして、その大きさの順番に表示する。

一個一個追っていくと

pageは辞書だが、簡単のためにtitleorderのタプルと考える。
そう考えると、最初は下のような順番になっている

[("カテゴリ一覧", None), 
 ("プライバシーポリシー", -99),
 ("タグ一覧", None),  
 ("管理者情報", -1)]
ここで、orderが定義されていないもの(Noneになっているもの)をselectattr('order', 'undefined')で取得すると、下のようなリストを得られる。
[("カテゴリ一覧", None), 
 ("タグ一覧", None)]
まずはこれを表示。

次に、orderが定義されているものをselectattr('order', 'defined')で取得すると、下のようなリストを得られる。

[("プライバシーポリシー", -99), 
 ("管理者情報", -1)]
これをsort(attribute='order')でソートすると、下のようなリストを得られる。
[("管理者情報", -1), 
 ("プライバシーポリシー", -99)]
これを表示すると、結果的に下のような順番で見える。
[("カテゴリ一覧", None), 
 ("タグ一覧", None), 
 ("管理者情報", -1), 
 ("プライバシーポリシー", -99)]

まとめ

正直あんまり良いとは思えない実装だと感じるが、デフォルト値の設定ができなさそうなので、これで妥協した。
もしorderのデフォルト値を設定できるなら、None値を0に設定したいところ。