WordPressでインクリメンタルサーチを自前で実装する

WordPressでインクリメンタルサーチを自前で実装する:


はじめに

『WordPress 検索』でググるとだいたい search.phpsearchform.php を使った同期的な検索の実装方法がヒットします。

非同期でインクリメンタルサーチを行う方法がパッと出てこなかったのでこの記事にまとめます。他により良い方法があればぜひ教えてください。


要件

  • カスタムポストを検索
  • 表示項目はサムネイルと名前
  • インクリメンタルサーチ
  • NIKE,ないき,ナイキのどれでもヒットするようにする


バージョン

WordPress 4.9.8 
Advanced Custom Fields 5.7.10 
Custom Post Type UI 1.6.1 
WP REST API 2.0-beta15 


完成形

こんなイメージになります。


incrementalsearch.gif



実装の流れ

  • 「ブランド」というカスタムポストを作る
  • カスタムポスト に検索用キーワードというカスタムフィールド を付与する
  • 表示項目の「サムネイル」はカスタムポスト のアイキャッチ画像で対応し「名前」はカスタムポスト のタイトルで対応する。
  • WP REST APIを使って検索結果はJSON形式で返すようにする
  • そのレスポンスを元にjQueryでゴリゴリ描画する


具体的な手順


必要なプラグインをインストールする

  • WP REST API
  • Advanced Custom Fields
  • Custom Post Type UI


スクリーンショット 2019-01-30 9.53.23.png




スクリーンショット 2019-01-30 14.23.27.png




スクリーンショット 2019-01-30 14.23.54.png



固定ページ「検索ページ」を作成する



スクリーンショット 2019-01-30 9.52.15.png



カスタムポスト 「ブランド」を作成する

メニューから「投稿タイプの追加と編集」を選択


スクリーンショット 2019-01-30 14.26.26.png


下記のように入力する



スクリーンショット 2019-01-30 20.08.43.png



カスタムフィールドを作る

検索用キーワードのカスタムフィールド を作る



スクリーンショット 2019-01-30 14.51.07.png


このカスタムフィールド グループをカスタムポスト 「ブランド」に紐づける


スクリーンショット 2019-01-30 14.51.20.png



カスタムポストを作成する

以下を入力してください。

- タイトル

- アイキャッチ画像

- 検索用キーワード

検索用キーワードにはヒットさせたい文字列を続けて入力してください。
NIKEでもないきでもナイキでもヒットさせたいので

「NIKEないきナイキ」としました。

この実装方法は一般的にはアンチパターンだとは思いますがWordPressだと他に実装方法が思いつきませんでした。



スクリーンショット 2019-01-30 14.53.15.png


同様に他にもデータを作成してください。今回はNIKEの他にadidasとUnderArmourを作りました。


functions.phpを編集する

以下をfunctions.phpに追加してください。

// rest_{post_type}_query 
add_filter( 'rest_brand_query', 'my_rest_brand_query', 10, 2 );  
 
function my_rest_brand_query( $args, $request ) { 
  // keywordというところはカスタムフィールド 「検索用フィールド」のslug名 
  if ( isset( $request['keyword'] ) ) { 
    $args['meta_query'] = array( 
      array( 
      "key" => "keyword", 
      "value" => $request['keyword'], 
      "compare" => "LIKE" // 部分一致なので"LIKE"とした。完全一致だったら"="にする 
      ) 
    ); 
   return $args; 
  } 
} 


固定ページの検索ページに対応するテンプレートを作成する

page-search.php を作成する
page-{固定ページのslug名}.php という命名規則。よくわからない人はテンプレートの優先順位を確認してください。

page-search.php
<?php 
get_header(); ?> 
 
<div class="wrap"> 
    <div id="primary" class="content-area"> 
        <main id="main" class="site-main" role="main"> 
 
 
        </main><!-- #main --> 
    </div><!-- #primary --> 
</div><!-- .wrap --> 
<?php get_footer(); 
 


検索フォームと検索結果を表示する領域を作る

page-search.php
<?php 
get_header(); ?> 
 
<div class="wrap"> 
    <div id="primary" class="content-area"> 
        <main id="main" class="site-main" role="main"> 
            <input id="search-form" type="search"> 
 
            <ul id="result-lists"></ul> 
 
        </main><!-- #main --> 
    </div><!-- #primary --> 
</div><!-- .wrap --> 
<?php get_footer(); 
 
 


Ajax通信でカスタムポスト を検索する処理を書く

page-search.php
. 
. 
省略 
<script> 
    jQuery(function($){ 
        $("#search-form").on("keyup", function(event){ 
            // 入力値が変更されたらとりあえず結果を消す 
            $("#result-lists").empty() 
            // 入力値が空だったら処理終了 
            if (event.target.value == "") { return } 
            $.ajax({ 
              // localhost:8000の部分は各自置き換えてください。 
              // _embedパラメータはアイキャッチ画像をレスポンスに含めるのに必要です。 
              // keywordパラメータに検索フォームの入力値を設定します。 
               url:"http://localhost:8000/wp-json/wp/v2/brand/?_embed&keyword=" + event.target.value, 
               type:'GET' 
            }) 
            // Ajaxリクエストが成功した時発動 
            .done( (data) => { 
                // 検索結果を描画する 
                refreshHTML(data) 
            }) 
            // Ajaxリクエストが失敗した時発動 
            .fail( (data) => { 
                // エラー処理 
            }) 
            // Ajaxリクエストが成功・失敗どちらでも発動 
            .always( (data) => { 
 
            }); 
        }) 
                // 検索結果描画用の関数 
        function refreshHTML(data) { 
            if (data.length > 0) { 
                $.each(data, function(index, val) { 
                    // タイトルは val.title.renderedで取得できる 
                    // 画像のURLは val._embedded["wp:featuredmedia"][0].source_urlで取得できる 
                    $("#result-lists").append("<li><img src=" + val._embedded["wp:featuredmedia"][0].source_url + " style='width: 50px; height: 50px; vertical-align: middle;'>" + val.title.rendered + "</li>") 
                }) 
            } 
        } 
    }) 
</script> 
とりあえずこれでインクリメンタルサーチができるはずです。

ただこれだとnikeで検索しようとした時に
nを打ったタイミングで通信が行われ
iを打ったタイミングで通信が行われ
kを打ったタイミングで通信が行われ
eを打ったタイミングで通信が行われ

という動きになります。

素早くniと打ったタイミングでは、nを打ったタイミングで行われた通信を中断してやるのが親切です。

つまり直前のリクエストを中断する処理があったほうが親切ということです。

それを次に書いて終わります。


直前のリクエストを中断する

page-search.php
. 
. 
省略 
<script> 
    jQuery(function($){ 
        // 追加 ajax中止用 
        var jqxhr; 
        $("#search-form").on("keyup", function(event){ 
            // 入力値が変更されたらとりあえず結果を消す 
            $("#result-lists").empty() 
            // 追加 直前のajax通信を中断する 
            if (jqxhr) { 
                jqxhr.abort(); 
            } 
            // 入力値が空だったら処理終了 
            if (event.target.value == "") { return } 
            // 追加Ajax通信 
            jqxhr = $.ajax({ 
              // localhost:8000の部分は各自置き換えてください。 
              // _embedパラメータはアイキャッチ画像をレスポンスに含めるのに必要です。 
              // keywordパラメータに検索フォームの入力値を設定します。 
               url:"http://localhost:8000/wp-json/wp/v2/brand/?_embed&keyword=" + event.target.value, 
               type:'GET' 
            }) 
            // Ajaxリクエストが成功した時発動 
            .done( (data) => { 
                // 検索結果を描画する 
                refreshHTML(data) 
            }) 
            // Ajaxリクエストが失敗した時発動 
            .fail( (data) => { 
                // ajax通信を中断した時もfailの方にくるのでエラー処理とは分けて考える 
                if (data.statusText == "abort") { return } 
                // エラー処理 
            }) 
            // Ajaxリクエストが成功・失敗どちらでも発動 
            .always( (data) => { 
 
            }); 
        }) 
                // 検索結果描画用の関数 
        function refreshHTML(data) { 
            if (data.length > 0) { 
                $.each(data, function(index, val) { 
                    // タイトルは val.title.renderedで取得できる 
                    // 画像のURLは val._embedded["wp:featuredmedia"][0].source_urlで取得できる 
                    $("#result-lists").append("<li><img src=" + val._embedded["wp:featuredmedia"][0].source_url + " style='width: 50px; height: 50px; vertical-align: middle;'>" + val.title.rendered + "</li>") 
                }) 
            } 
        } 
    }) 
</script> 
これでこのような動きが実現できると思います。

再掲



incrementalsearch.gif


コメント

このブログの人気の投稿

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-04-30 23:37:32 RSSフィード2021-04-30 23:00 分まとめ(42件)

投稿時間:2023-02-05 02:09:04 RSSフィード2023-02-05 02:00 分まとめ(9件)