やっと、off-canvas と dropdown の切り替えができるCSSだけで実装したレスポンシブナビゲーションメニューが完成した。
もちろん、全部自分だけで作れる技量もなく、世界中を旅しながら(ネットだけど)CSSテンプレート探しまわり、そのテンプレートに合う html を吐き出すようにしました。
wordpressのテーマとして作っているので、wp_nav_menu()で普通に出力しても、求めている htmlコード にはならず、困った困ったと、フックをかけて何とかしてやろうと、処理方法を探しまわったところ「カスタムウォーカー機能」という、高いレベルで htmlコード をカスタマイズ出来ることが分かりました。
使い方はくせがあるように思いますが、結果的にはそうでもなかったので、メモとして残しておきます。
まず、呼び出し方
1 2 3 4 5 6 7 8 |
wp_nav_menu( array( 'theme_location' => 'main_navigation', 'container' => 'nav', 'container_id' => 'menu', 'echo' => true, 'items_wrap' => '<ul>%3$s</ul>', 'walker' => new cs_walker_nav_menu ) ); // thanks nick |
wp_nav_menu 関数の引数 array に walker というキーを追加し、Walker_Nav_Menu を継承した cs_walker_nav_menu というクラスを new します。
さて、 s_walker_nav_menu とはなんぞやという話になりますのでコードを貼り付けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
class cs_walker_nav_menu extends Walker_Nav_Menu { function start_lvl( &$output, $depth ) { $output .= ""; } function end_lvl( &$output, $depth ) { $output .= ""; } function start_el( &$output, $item, $depth, $args ) { if (in_array('menu-item-has-children', $item->classes)) { // 親の場合 $output .= "\n".'<li>'; $output .= $this->create_a_tag($item, $depth, $args); $id = "ssid-".$item->ID; $caption = $item->title; $output .= "\n" . $indent . '<label for="'.$id.'" class="toggle-sub" onclick="">►</label>'; $output .= "\n" . $indent . '<input type="checkbox" id="'.$id.'" class="sub-nav-check">'; $output .= "\n" . $indent . '<ul id="'.$id.'-sub" class="sub-nav">'; $output .= "\n" . $indent . '<li class="sub-heading">'.$caption; $output .= "\n" . $indent . '<label for="'.$id.'" class="toggle" onclick="" title="Back">►</label>'; } else { // 子の場合 $output .= '<li>'; $output .= $this->create_a_tag($item, $depth, $args); } } function end_el( &$output, $item, $depth, $args ) { if (in_array('menu-item-has-children', $item->classes)) { // 親の場合 $output .= "\n".'</li></ul></li>'; } else { // 子の場合 $output .= "\n".'</li>'; } } private function create_a_tag($item, $depth, $args) { // link attributes $attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : ''; $attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : ''; $attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : ''; $attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : ''; //$attributes .= ' class="menu-link ' . ( $depth > 0 ? 'sub-menu-link' : 'main-menu-link' ) . '"'; $item_output = sprintf( '%1$s<a%2$s>%3$s%4$s%5$s</a>%6$s', $args->before, $attributes, $args->link_before, apply_filters( 'the_title', $item->title, $item->ID ), $args->link_after, $args->after ); return apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args ); } } ?> |
cs_walker_nav_menu クラスは 5つのメソッドから構成しています。そのうち4つは、Walker_Nav_Menu クラスのメソッドをオーバーライドして乗っ取ります。
- function start_lvl ()
- function end_lvl ()
- function start_el ()
- function end_el ()
lvl は level の略で階層の事を意味します。1段目の階層には反応せず、2段目の階層を出力する時から反応します。
- start_lvl では <ul> を出力するが一般的です。
- end_lvl では </ul> を出力するが一般的です。
一方 el は elemnt の略で要素の事を意味します。この場合だとメニュー項目ごとに反応します。
- start_el では <li><a href=”#”>xxx</a> を出力するが一般的です。
- end_el では </li> を出力するが一般的です。
この一般的な出力を変更することで、自在に htmlコード を操ることが出来ます。
今回行ったの、階層を出力する start_lvl と end_lvl を使わずに、 start_el と end_el で子の階層を持っているか判断し、出力するというものです。
start_el と end_el の引数である $item がかなり有効で var_dump して内容を確認しておくことをお勧めいたします。
この $item に classes というキーがあり、子持ちの要素の場合は、”menu-item-has-children” という文字列が格納されます。子持ちじゃない場合は格納されていません。
それを利用すれば、 start_lvl と end_lvl を使用しなくても階層処理は可能です。特に今回は <ul> の前後に htmlタグ を挿入するだけでなく、ユニークな id を付ける必要がありましたので、 element で処理をするようにしました。
みなさんも $item を活用して、いろいろとメニューを作ってみてくださいね。
コメント