さて、WPテーマ自作記もついに5回目を迎えました! 祝!
折りたたみメニュー化にトライ
前回までで、_sのテーマを一応レスポンシブにして、メニューまわりの調整をいたしましたけれども、今回はスマホ表示時の折りたたみメニュー実装編でございます。
実はわたくし、何を隠そう JavaScript が苦手でして、ずっと避けてまいりました。PHPやPythonは書くけれども、JSは、触らないで済ますことができるならば、触らない、という方針でやってまいりました。ので、jQueryとかも、カッコが多くてよくわかんねー、とかずっと思って敬遠してまいりましたが、オリジナルテーマを作ろうというような輩が、どっかから持ってきたよくわからないjsをのっけて良しとするわけにもいかないよねってことで、殊勝にも入門書を買ってみたり、いろいろググりつつお勉強をいたしました。
で、やってみたら、けっこう簡単にできるじゃねえか、ということで、これまでのわたくしは何だったのだと、バカかと。こんなことなら、とっとと勉強しておけばよかったなと反省しきりにございましゅ。
というわけで、まずは現状スマホ表示時に働いている_sにデフォルトでついてくる「navigation.js」とは別に「my-navigation.js」を作って、WordPressに読み込ませます。
「functions.php」の120行目くらいに「function テーマ名_scripts()」がありますので、そこに、
wp_enqueue_script( ‘テーマ名-my-navigation', get_template_directory_uri() . '/js/my-navigation.js', array('jquery'), '20151215', true );
を入れてあげましょ−。「テーマ名」となっているところは、それぞれのテーマ名が入りますよ。「20151215」の数字は他のも入ってるから入れてるってだけで、特になくても大丈夫だと思います。
そんでもって「my-navigation.js」を書いていきます。折りたたみメニューにはやはりjQueryが便利なようです。WordPressのファイル群にはjQueryも含まれておりますので、上記の「wp_enqueue_script」の3番目の引数は当該スクリプトが依存するスクリプトを書くことになっていて、その配列に「jQuery」を入れるだけで、特に何もしなくても、WordPressがjQueryを読み込んでくれるようになります。
また、WordPressでjQueryを使う場合は、いきなり「$」を使っても動かないそうなので、まずはjQueryの基本である
jQuery(function($){ … });
を書いて、その間で「$」で始まるコードを書いていくようにいたしましょう。
まずは子メニュー・孫メニューの折りたたみ
さて、最初は子メニュー、孫メニューをボタンで折りたためるようにしたいわけですが、jQueryを使うとたった4行でできちゃうんですね。
$('.menu-item-has-children > a').before('<button class="sub-menu-button">open</button>'); $('.sub-menu-button').on('click',function(){ $(this).next('a').next('ul').slideToggle('fast'); });
まず、メインメニューの中で子要素を持つものにボタンを持たせなければならないですが、すでに_sではそういう要素には「.menu-item-has-children」というクラスを作ってくれているので、その兄弟の「a」要素の前に「before()」メソッドでボタンのhtml要素を付加しています。after()だとボタンが「a」のリンクのhoverの下に隠れちゃうので、before()にしました。
そしてそのボタンをクリックしたら、そのボタンの次のa要素のそのまた次にあるul要素のdisplayをblockにしたりnoneにしたりをトグルして、さらにそれをアニメーションで表示してくれるjQueryの「sileToggle()」メソッドをあてているわけです。
これだけで、孫要素も含めて、一気に折りたたみメニューができちゃいました。スゲエ。いや、ほんとに、これまでjQueryとか触ってこなかったのはほんとにバカだったと思います。深く反省いたします。
ボタンの位置やら見た目等々は「.sub-menu-button」のクラスで適宜調整してくださいねー。
折りたたみボタンにアイコンを
さて。現状、ボタンに「open」とか書いてあるのに、子メニューが表示されようがされまいが表示が一向に変わらないのはよろしくないでございますね。ここはよくあるパターンですが、トグルで「V」と「へ」みたいな感じにしたいじゃないですか。
で、そういったアイコンは WebFont を使うと便利だよということで、当初はAutomattic社ご提供のGnericonsを使おうかと思いましたが、サイトでiconをクリックして表示されるコードをコピペしても全く表示できず、ググってもどうも解決策が見出せなかったので、Font Awesome にしました。
さきほども手を加えた「functions.php」の120行目くらいにある「function テーマ名_scripts()」に、下記を加えます。
wp_enqueue_script( 'font_awesome', 'https://use.fontawesome.com/releases/v5.0.6/js/all.js', array(), '20151215', true );
それから、本家サイトの「ions」で「chevron-up」と「chevron-down」をクリックして、それらのページの下部にあるテキストエリアから「<i class=”fas fa-chevron-down”></i>」といったhtml要素をコピーしておきましょう。
さきほど、slideToggle()メソッドを組み込んだfunctionに、メニューが展開されているかいないかを示す「expanded」というクラスを付加することにして、そのクラスが存在している時は「chevron-up」を、そうでなければ「chevron-down」を表示させる、ということを追加すると、
$('.sub-menu-button').on('click',function(){ $(this).toggleClass('expanded'); $(this).next('a').next('ul').slideToggle('fast'); if($(this).hasClass('expanded')){ $(this).html('<i class="fas fa-chevron-up"></i>'); } else { $(this).html('<i class="fas fa-chevron-down"></i>'); }; });
といった具合になります。
メインメニューにも自作JSを
さて、これで子孫メニューが折りたたみになりましたが、どうでしょう。肝心のメインメニューのボタンを押すと、無愛想に表示/非表示が切り替わるだけなのが気になってくるじゃぁありませんか。
この際、メインメニューのボタンにもこの「my-navigation.js」を当ててみましょう。そのために、まずは「functions.php」の125行目あたりにある
//wp_enqueue_script( 'テーマ名-navigation', get_template_directory_uri() . '/js/navigation.js', array(), '20151215', true );
を上記のようにコメントアウトして「navigation.js」を無効にします。
それから、メインメニューボタンにjQueryのメソッドをあてていくわけですが、基本はさきほどのサブメニューボタンのロジックと同じです。ただ「navigation.js」のメインメニューの表示/非表示の切り替えは「.main-navigation」に「.toggled」というクラスを付加して、その「ul」のdisplayをコントロールしているので、そのままではjQueryのslideToggle()が使えません。
そこで、_sでは「.main-navigation ul」に「#primary-menu」というidが付加されているので、それを使います。またアイコンは「bars」と「times」を使い、
$('.menu-toggle').on('click', function(){ $(this).toggleClass('expanded'); if($(this).hasClass('expanded')) { $(this).html('<i class="fas fa-times"></i>'); } else { $(this).html('<i class="fas fa-bars"></i> MENU'); } $('#primary-menu').slideToggle('fast'); });
てな具合にいたします。
さて、これで動作確認をいたしますと、あら大変、ボタンを押すとスライドで開かれるメニューはPC表示の時の横並びのメニューではありませんか。これは「navigation.js」を無効化したことで「.main-navigation」に付加されていた「.toggled」クラスが付加されなくなったことで、「_menus.scss」の「/* Small menu. */」のところで指定していた「.main-navigation.toggled ul」のルールが適用されなくなってしまったからなんですね。なので、単純にそこから「.toggled」を削除してあげますと、ちゃんとスマホメニュー用のメインメニューが表示されるようになります。
これで、ほぼ完成ですが、このメインメニューボタン、クリックするまではアイコンではなく「メニュー」という文字が表示されちゃってますよね。「header.php」の47行目あたりの「esc_html_e( )」の最初の引数の文字列がそのまま表示されるわけですが、そこに「bars」のアイコンの「<i class=”fas fa-bars”></i>」を入れても、html要素がそのまま表示されるだけなので、これは下記のように、
$(document).ready(function(){ $('.menu-toggle').html('<i class="fas fa-bars"></i> MENU'); })
と、文書が読まれた段階で、ボタンに表示された文字列を書き換えるようにします。完成版「my-navigation.js」は下記のようになります。
完成版JS
jQuery(function($){ $(document).ready(function(){ $('.menu-toggle').html('<i class="fas fa-bars"></i> MENU'); }) $('.menu-toggle').on('click', function(){ $(this).toggleClass('expanded'); if($(this).hasClass('expanded')) { $(this).html('<i class="fas fa-times"></i>'); } else { $(this).html('<i class="fas fa-bars"></i> MENU'); } $('#primary-menu').slideToggle('fast'); }); $('.menu-item-has-children > a').before('<button class="sub-menu-button"><i class="fas fa-angle-down"></i></button>'); $('.sub-menu-button').on('click',function(){ $(this).toggleClass('expanded'); $(this).next('a').next('ul').slideToggle('fast'); if($(this).hasClass('expanded')){ $(this).html('<i class="fas fa-chevron-up"></i>'); } else { $(this).html('<i class="fas fa-chevron-down"></i>'); }; }); });
「_menus.scss」の「/* Small menu. */」のところは下記のような具合。
/* Small menu. */ @media screen and (max-width: $low-breakpoint) { .main-navigation { border-top: $normline; border-bottom: $normline; } .main-navigation ul { display: none; li { float:none; border-bottom: $hairline; &:last-child { border-bottom: none; } ul { margin-left: 2rem; li { &:first-child { border-top: $hairline; } } } } .sub-menu-button { float: right; margin: 0.5rem 0.5rem 0 0; border: none; background-color: $color__navigation-bar; font-size: 1rem; color: #000; } .sub-menu { display: none; } } .menu-toggle { display: block; margin: 0.5rem; padding: 0.5rem; border:none; background: $color__navigation-bar; font-size: 1rem; } }
というわけで、ようやくこれで、_sのテーマのカスタマイズの基本ができたかなという感じです。今後はこれをベースに細かい見た目を作っていけばいいかなと。