ライトニングに検索ボタンを追加する方法

記事もだいぶ増えてきましたので、そろそろ検索機能があった方がいいかもしれません。そこで今回はこのサイトで使用しているテーマ(Lightning)に検索ボタンを付けてみます。検索ボタンはWordpressの管理画面(ダッシュボード)にある「外観」→「ウィジェット」から追加できますが、トップページの上部だったり左右のサイドバーの上部などにしか追加できない様です。

他のサイトを見てみると、ページの上部にある「ナビゲーションバー」などと呼ばれている部分についていることが多い様なので、同じ様にできないかやってみます。

WordPressの検索機能を追加して調べます

まず検索機能を調べるために、Wordpressの検索ウィジェットを追加します。どこでも同じと思われますが、今回はサイドバー(共通上部)と呼ばれる部分に追加します。

管理画面(ダッシュボード)にある「外観」→「ウィジェット」からサイドバー(共通上部)を選択します。「+」ボタンを押して表示された画面に「検索」と入力して検索ウィジェットを追加します。

「更新」ボタンを押して何かページを表示すると検索ボタンが追加されています。

どの様なHTMLが追加されたのか調べるために、Chrome画面で「検索」ボタンを右クリックして表示されたメニューから、「検証」を選択して該当箇所を表示します。

追加されたHTMLをコピーすると以下の様になっています。

<form role="search" method="get" action="http://mimura-soft.local/blog/" class="wp-block-search__button-outside wp-block-search__text-button wp-block-search">
    <label class="wp-block-search__label" for="wp-block-search__input-1">検索</label>
    <div class="wp-block-search__inside-wrapper ">
        <input class="wp-block-search__input form-control" id="wp-block-search__input-1" placeholder="" value="" type="search" name="s" required="">
        <button aria-label="検索" class="wp-block-search__button wp-element-button" type="submit">検索</button>
    </div>
</form>

このままでは情報量が多いので、検証ツールの「ネットワーク」タブを選択して、検索欄に何か入力して実行してみます。URL欄にもありますが、<自分のサイト名>/blog/?s=<検索ワード>という様に、「s」パラメータに検索ワードを指定して自分のサイトに送信すると検索結果を返してくれる様です。

検索に直接関係しない項目を削除していくと、最低限以下の形になっていれば検索機能が実現できる様です。

<form action="http://mimura-soft.local/blog/" method="get">
    <div>
        <input placeholder="サイト検索" name="s" required />
        <button type="submit">検索</button>
    </div>
</form>
検索ボタンを追加する場所を調べます

検索ボタンの時と同様にChromeの検証機能を使用して、ナビゲーションバー付近の要素を調べます。特徴的なクラス名(gMenu_outer)がありましたので、Lightningテーマのフォルダ内を検索してみます。

Lightningのフォルダを検索すると、「_g2」フォルダ内の「header.php」ファイル内に該当する箇所がありました。しかしこのままでは追加できそうもないので、ブレークポイントを設定してステップ実行してみます。

ステップ実行を進めていくと、最終的にWordpressのメソッド(wp_nav_menu)の302行目辺りで「wp_nav_menu」というフィルターフックが呼ばれて、ナビゲーション要素が作成される様です。処理の一番最後に検索ボタンを追加したいので、このフックにLightningより低い優先順位のフックメソッドを定義すれば、検索ボタンを追加できそうです。フックメソッドは以前ご紹介した「子テーマ」を使用すると実装できます。

子テーマを作成します

方針が決まりましたので、以下の場所に子テーマフォルダ(mylightning等)を作成します。

<Wordpress>
└─wp-content
    └─themes
        └─<ここに作成します>

作成したフォルダ内に、「style.css」というファイルを作成して、以下の様なコメントを書き込みます。最低限コメント内の「Template」項目(親テーマフォルダ名)さえあればWordpressに子テーマとして認識されます。他の項目はテーマの詳細情報として表示されますので、ご自身の状況にあわせて修正してください。

/*
Theme Name: My Lightning
Author: yuuji mimura
Description: カスタマイズ版Lightningテーマ
Version: 1.0
Template: lightning
*/

追加で「functions.php」という空のファイルも作成します。全体的には以下の様な構成になります。

wp-content
└─themes
    └─mylightning
       ├─style.css
       └─functions.php

最後にフォルダとファイルの所有者を変更しておきます。

chown -R www-data:www-data ./<子テーマフォルダ>

以上で子テーマの作成は終了です。Wordpressでテーマが表示されているのを確認して有効化します。

子テーマを修正します

まずはどの様な文字列(HTML要素)が渡ってくるのか調べるために、「functions.php」ファイルを以下の様に修正します。「add_search_form」メソッドの引数は、先ほどのWordpressの「apply_filters」メソッドの引数から推測しました。9行目のフィルター追加関数の3番目の引数は実行する優先順位で、デフォルトが10なのでそれより低めの優先順位にしてあります。(「0」が一番優先順位が高い様です。) 4番目の引数はadd_search_formメソッドに渡す引数の個数になっています。

<?php
// 検索フォームをナビゲーションバーに追加します
function add_search_form($nav_menu, $args)
{
    return $nav_menu;
}

// ナビゲーションメニュー作成用フィルターフックを追加します
//add_filter('wp_nav_menu', 'add_search_form', 30, 2);

「add_search_form」メソッドにブレークポイントを設定して調べてみると、引数($nav_menu)に以下の様な文字列が渡されている様です。(見やすい様に整形してあります。) この文字列内の「<ul」タグと最初の「<li」タグの間に検索フォームを追加すれば表示してくれそうです。

<nav class="menu-%e3%83%98%e3%83%83%e3%83%80%e3%83%bc%e3%83%a1%e3%83%8b%e3%83%a5%e3%83%bc-container">
    <ul id="menu-%e3%83%98%e3%83%83%e3%83%80%e3%83%bc%e3%83%a1%e3%83%8b%e3%83%a5%e3%83%bc" class="menu gMenu vk-menu-acc">
        <li id="menu-item-32" class="menu-item menu-item-type-taxonomy menu-item-object-category">
            <a href="http://mimura-soft.local/blog/category/blog/"><strong class="gMenu_name">ブログ</strong></a>
        </li>
        <li id="menu-item-33" class="menu-item menu-item-type-post_type menu-item-object-page">
            <a href="http://mimura-soft.local/blog/info/"><strong class="gMenu_name">お問い合わせ</strong></a>
        </li>
    </ul>
</nav>

まずは検索フォームを作成するメソッドを「functions.php」ファイルに追加します。HTML要素を文字列で取得したいので、「ob_start」と「ob_get_clean」メソッドを使用しています。直接文字列で書いても結果は同じですが、実際のHTML要素として書いておくと、エディタの整形機能やエラーチェックが有効になるので便利かもしれません。

<?php
// 検索フォームを作成して文字列で返します
function create_search_form()
{
    ob_start();
?>
    <form action="<?php echo esc_url(home_url('/')); ?>" method="get">
        <span>
            <input id="input-1" placeholder="サイト検索" name="s" required />
            <button type="submit">検索</button>
        </span>
    </form>
<?php
    $text = ob_get_clean();

    return $text;
}
?>

先ほどの「add_search_form」メソッドを以下の様に修正します。

// 検索フォームをナビゲーションバーに追加します
function add_search_form($nav_menu, $args)
{
    $form = create_search_form();
    
    $nav_menu = preg_replace('/(<ul.*?>)/', "$1{$form}", $nav_menu);

    return $nav_menu;
}

ページを再読み込みすると、上手く表示されました。

少し上方向に位置がずれていますが、ライトニングはテーマの中でBootstrapがそのまま使用できますので、好きな様に位置やデザインを変更できます。また、せっかくなので以前ご紹介したメイン画面から縦棒を消すメソッドも追加して、最終的に以下の様になりました。(検索フォームは表示位置だけ調整しました。お好みのデザインに修正してください。)

<?php
// タイトルの書き換え機能を有効化します
add_theme_support('title-tag');

// トップページの場合はサイト名のみを返すフィルターフックを追加します
add_filter('pre_get_document_title', function ($title) {
    return is_front_page() ? get_bloginfo('name') : $title;
}, 30, 1);

// 検索フォームを作成して文字列で返します
function create_search_form()
{
    ob_start();
?>
    <form class="mt-2 mr-1" action="<?php echo esc_url(home_url('/')); ?>" method="get">
        <span>
            <input id="input-1" placeholder="サイト検索" name="s" required />
            <button type="submit">検索</button>
        </span>
    </form>
<?php
    $text = ob_get_clean();

    return $text;
}

// 検索フォームをナビゲーションバーに追加します
function add_search_form($nav_menu, $args)
{
    if ($args->container === 'nav' || str_contains($nav_menu, 'vk-mobile-nav-menu-outer') {
        $form = create_search_form();

        $nav_menu = preg_replace('/(<ul.*?>)/', "$1{$form}", $nav_menu);
    }

    return $nav_menu;
}

// ナビゲーションメニュー作成用フィルターフックを追加します
add_filter('wp_nav_menu', 'add_search_form', 30, 2);

30行目にあるif文は、このフィルターフックは色々な場所にあるメニュー項目を作成するのに使用されているため、ナビゲーションバー以外にあるメニュー項目(フッター等)に検索フォームが追加されない様に条件判定しています。str_contains関数は逆に、モバイル端末等で表示される、ハンバーガーボタン(三)と呼ばれるメニューに検索フォームを追加するための判定を行っています。

何とか検索フォームを付けることができました。よろしかったらお試しください。