WEB・アプリ開発

Middlemanでcontent_forとyield_contentで超柔軟にlayoutを変更する方法

テンプレートからlayoutを微妙に変えられるcontent_forとyield_content

たとえば、記事ページと一覧ページでサイドバーの内容を変えたい時、どうしますか?Layout側でIf文で出し分けるという方法もありますね。
でも、Middlemanではそのような場合はcontent_foryield_contentを使うとコードの見通しが良くなります。

公式ページのこのページにある例を少し変えて説明します。

layout.erb


hello.erb


こうすることで、最終的に以下のようなhtmlが生成されます。


テンプレートからcontent_forでなんらかのコンテンツをセットしてあげて、レイアウト側から取り出すことができます。yield_contentのよい点は、仮にテンプレート側でcontent_forで何もセットしていない場合、エラーにならず何も出力しないことです。

この仕組みによって、テンプレートからメインコンテンツ以外(たとえばサイドバーやメニュー)を微妙に変えたい時など、レイアウト側のコードをif文などで汚さずに、テンプレート側で書くことができます。あるべきコードがあるべきところにあり見通しが良くなります。

Nested Layout(入れ子レイアウト)でも使えるcontent_forとyield_content

Middlemanではwrap_layoutというヘルパーメソッドを使うことで、レイアウトを何重にも入れ子にすることができます。このNested Layout(入れ子レイアウト)でもcontent_forとyield_contentは大活躍します。

公式ドキュメントのこのページにある例を少し変更して説明します。ただ、erbだと現状Nested Layout(入れ子レイアウト)は動かないので、slimに変換して説明します。(erbだと動かない理由は以下をご覧ください)

Middlemanでwrap_layoutがドキュメント通りに動かない件ドキュメント通りにしてもhtmlが何も出力されないという問題 公式ドキュメントのこの部分によると、Nested Layoutを使いたい...

入れ子の親が以下のようだとします。

layout.slim


子は以下のようだとします。

article_layout.slim


これで、子側で設定した:sub_contentに”なんらかのコンテンツ”という文字列がセットされ、親側のレイアウトで取り出すことができます。
階層構造としては、テンプレート→子レイアウト→親レイアウトとなります。子レイアウトが何重になっても大丈夫です。

個人的に柔軟で便利だと思うのは、下の階層でcontent_forでセットしたコンテンツはそれより上ならどこの階層でもyield_contentで取り出してもOKです。なので、前述の例だと、テンプレートでセットしたものを、子レイアウトでも取り出してもいいし、親レイアウトで取り出してもOKです。

スポンサーリンク

content_forとwrap_layoutの順番に注意

子レイアウトでの書き方で注意しなければならない点があります。content_forwrap_layoutの順番です。以下のように、content_forを後ろに書くと親側で取り出すことができません。(何も出力されない。)

まとめ

いかがでしたでしょうか。レイアウト側にif文などで全てのコンテンツを書いていた方は一度、content_foryield_contentやNested Layoutを試してみてはいかがでしょうか。コードがわかりやすくなり、メンテナンスしやすくなるのは間違いないです。

※Middlemanのバージョン: 3.4.0