LoginSignup
20
21

More than 5 years have passed since last update.

flexible SearchとMTを組み合わせて使ってみた

Last updated at Posted at 2016-02-10

MovableTypeで検索ページを実現したかったのですが、DataAPIでは実現できなかったのでflexible Searchを利用して実現したときのメモ。

仕様(実現したいこと)

記事

  • MovableTypeで登録
  • カテゴリは4つ
  • カスタムフィールド2つ(所属、団体名)

検索ページ

  • カテゴリ、カスタムフィールド、キーワードで検索
  • 結果を一覧に表示、ページングあり
  • 一覧は全カテゴリを含むページと、各カテゴリごとの計5ページ

実装

基本的にはGitHubのページに載っているので、こちらを参照してもらえれば実現できます。

検索用JSONファイルの出力

検索対象のJSONファイルの出力が必要になります。これはMovableTypeで行います。
カスタムテンプレートを以下のような感じで作成します。
速度を少しでも早くしたい場合は、カテゴリごとに出力した方が良いです。

entries.json
<mt:Unless name="compress" regex_replace="/^\s*\n/gm","">
<mt:SetVar name="items">
<mt:Entries include_blogs="1" lastn="0">
<mt:SetVarBlock name="item{date}"><$mt:EntryDate format="%Y.%m.%d"$></mt:SetVarBlock>
<mt:SetVarBlock name="item{title}"><mt:EntryTitle></mt:SetVarBlock>
<mt:SetVarBlock name="item{url}"><mt:EntryPermalink></mt:SetVarBlock>
<mt:SetVarBlock name="item{body}"><mt:EntryBody remove_html="1" regex_replace="/\n|\t| | /g",""></mt:SetVarBlock>
<mt:SetVarBlock name="item{excerpt}"><$mt:EntryExcerpt$></mt:SetVarBlock>
<mt:SetVarBlock name="item{more}"><mt:EntryMore remove_html="1" regex_replace="/\n|\t| | /g",""></mt:SetVarBlock>
<mt:SetVarBlock name="item{tag}">,<mt:EntryTags glue=","><mt:TagName regex_replace="/ | /g","%20"></mt:EntryTags>,</mt:SetVarBlock>
<mt:SetVarBlock name="item{category}"><mt:EntryCategories glue=","><mt:CategoryLabel></mt:EntryCategories></mt:SetVarBlock>
<mt:SetVarBlock name="item{group}"><$mt:CFGroup$></mt:SetVarBlock>
<mt:SetVarBlock name="item{circle}"><$mt:CFCircle$></mt:SetVarBlock>
<mt:SetVarBlock name="items" function="push"><mt:var name="item" to_json="1"></mt:SetVarBlock>
</mt:Entries>
{"items":[
<mt:Loop name="items" glue=","><mt:Var name="__value__"></mt:Loop>
]}
</mt:Unless>
  • <mt:SetVarBlock name="item{date}">で指定しているitem{date}dateの部分は後々使用するので、わかりやすい名前にしておいた方がよいです
  • <$mt:CFGroup$><$mt:CFCircle$>はカスタムフィールドです

flexibleSearchの設定

今回オプションに設定したのは以下です。

検索用JSONファイルパス(searchDataPath)

MovableTypeで出力するパスです。

flexibleSearch-cate.js
    searchDataPath: '/data/entries.json',

フォームHTML(searchFormHTML)

検索フォーム部分のHTML。

flexibleSearch-cate.js

searchFormHTML: [
         '<div>\r\n',
           '<form action="index.html" method="get">\r\n',
            '<div>\r\n',
              '<label for="group">所属</label>\r\n',
              '<select name="g" id="group">\r\n',
                '<option value="" selected="selected">選択してください</option>\r\n',
                '<option value="1">所属1</option>\r\n',
              '</select>\r\n',
            '</div>\r\n',

            '<div>\r\n',
              '<label for="circle">団体名</label>\r\n',
              '<select name="c" id="circle">\r\n',
                '<option value="" selected="selected">選択してください</option>\r\n',
              '</select>\r\n',
            '</div>\r\n',
            '<fieldset>\r\n',
              '<legend>カテゴリ</legend>\r\n',
              '<label><input type="checkbox" name="cat[]" id="category1" value="1"><span id="category1_label">カテゴリ1</span></label>\r\n',
              '<label><input type="checkbox" name="cat[]" id="category2" value="2"><span id="category2_label">カテゴリ2</span></label>\r\n',
              '<label><input type="checkbox" name="cat[]" id="category3" value="3"><span id="category3_label">カテゴリ3</span></label>\r\n',
              '<label><input type="checkbox" name="cat[]" id="category4" value="4"><span id="category4_label">カテゴリ4</span></label>\r\n',
            '</fieldset>\r\n',
            '<div>\r\n',
              '<label for="keyword">キーワード</label>\r\n',
              '<input type="text" name="search" id="keyword" value="">\r\n',
            '</div>\r\n',

            '<div>\r\n',
              '<input type="submit" id="submitButton" value="検索">\r\n',
            '</div>\r\n',
            '<input type="hidden" name="offset" value="0">\r\n',
            '<input type="hidden" name="limit" value="6">\r\n',
          '</form>\r\n',
        '</div>\r\n',
        ].join(""),
  • <input type="hidden" name="offset" value="0">は必ず必要
  • <input type="hidden" name="limit" value="6">も必ず必要。valueは環境に合わせて。
  • <input type="text" name="search" id="keyword" value="">も必ず必要。name=searchが大事。
  • 末尾に改行(\r\n)を入れているのは見た目ではなく、このdivに「display: inline-block;」を指定している場合、改行を入れないとレイアウトが崩れるためです。

検索結果一覧(resultItemTmpl)

検索結果の一覧部分。

flexibleSearch-cate.js
        resultBlockId: "news-list",
        resultItemTmpl: [,
    '{{#items}}',
      '<li>',
        '<h3>{{group}}:{{circle}}</h3>',
        '<h4><a href="{{url}}">{{title}}</a> ({{date}})</h4>',
        '<p>{{&excerpt}}</p>',
      '</li>',
    '{{/items}}',
        ].join(""),
  • resultBlockIdは検索結果を挿入する要素のIDを指定します。jqueryでいうappend対象。
  • resultItemTmplは一覧部分。この辺はMT書いてる人ならなんとなくわかるはず。使われているurl、image等の名前は出力したjsonファイルのitem{url}に合わせて指定します。

ページタイトル(resultMetaTitleTmpl)

ページタイトルが自動的に変更されるのでそれを修正。

flexibleSearch-cate.js
        resultMetaTitleTmpl: [ 
        "{{metaTitle}}"
        ].join(""),

ページング(paginateTmpl)

flexibleSearch-cate.js
        paginateTmpl: [
        '<div class="paging fs-paginate" id="fs-paginate">',
          '<ul>',
          '{{#showTurnPage}}',
          '{{#exceptFirst}}',
             '<li class="fs-prev"><a class="fs-prev-link fs-turn-page-link" href="#" title="{{prevPageText}}">{{&prevPageText}}</a></li>',
          '{{/exceptFirst}}',
          '{{/showTurnPage}}',

          '{{#page}}',
          '{{#checkRange}}',
             '<li class="{{current}}"><a class="fs-page-link {{currentLink}}" href="#" title="{{pageNumber}}">{{pageNumber}}</a></li>',
          '{{/checkRange}}',
          '{{/page}}',

          '{{#showTurnPage}}',
          '{{#exceptLast}}',
            '<li class="fs-next"><a class="fs-next-link fs-turn-page-link" href="#" title="{{nextPageText}}">{{&nextPageText}}</a></li>',
          '{{/exceptLast}}',
          '{{/showTurnPage}}',
          '</ul>',
        '</div>'
        ].join(""),
        paginateCount: 6,
        showTurnPage: true,
        prevPageText: 'Prev',
        nextPageText: 'Next',
        maxPageCount: 10,
  • {{#exceptFirst}}が「Prev」、{{#exceptLast}}が「Next」の部分
  • hrefは#でOK。flexibleSearchがよしなにしてくれる
  • 自分だけなのかもしれないが、classとtitleを設定してあげないと正しくページングが動いてくれなかった
  • maxPageCountはありがたい

独自の検索(customSearch)

flexibleSearchではキーワード検索は行えるが、カテゴリやカスタムフィールドの検索までは行えないので、その辺はこのエリアで独自に実装する必要がある。
return false;にすると結果から除外される。

flexibleSearch-cate.js
        customSearch: function(item, paramObj){
            var group = $('#group').val();
            var circle = $('#circle').val();
            var groupText = $("#group option:selected").text();
            var circleText = $("#circle option:selected").text();

            // Group
            if (group != '') {
                if (item.group != groupText) {
                    return false;
                }
                else {
                    // Circle
                    if (circle != '') {
                        if (item.circle != circleText) {
                            return false;
                        }
                    }
                }
            }

            // Category Check
            var arrCategory = new Array();
            var bCategory = false;
            for (var i = 1; i <= 4; i++) {
                if ($('#category' + i).prop('checked')) {
                    arrCategory.push($('#category' + i + '_label')[0].innerText);
                    bCategory = true;
                }
            }

            if (bCategory) {
                var myCategory = item.category.split(',');
                var bCategoryMatch = false;

                for (var j = 0; j < myCategory.length; j++) {
                    if ($.inArray(myCategory[j], arrCategory) >= 0) {
                        // 対象
                        bCategoryMatch = true;
                        break;
                    }
                }

                if (!bCategoryMatch) {
                    // 対象外
                    return false;
                }
            }

            return true;
        },

ページングHTMLの変更(modifyPaginateHTML)

あまりないかもしれませんが、今回は表示中のページ番号はクリックできないようなHTMLだったので、変更する必要がありました。そういう場合はこのエリアで変更できます。

flexibleSearch-cate.js
        modifyPaginateHTML: function(html){
            // current change
            var searchStartStr = '<li class="fs-current">';
            var searchEndStr = '</li>';
            var start = html.indexOf(searchStartStr);
            if (start != -1) {
                var end = html.indexOf(searchEndStr, start);
                start = parseInt(start) + searchStartStr.length;

                var before = html.substring(start, end);
                var title = $(before).attr('title');
                html = html.replace(before, '<em>' + title + '</em>');
            }

            return html;
        },

その他

  • 初期表示で検索結果を表示したかったのですが、うまいこといきませんでした。なので、初期表示は独自でjqueryで実装しました。
  • ページングのリンクは、クリックされたあとにflexibleSearchで自動で計算されるようです
  • 検索対象データ(JSONファイル)が0件の場合、customSearchは動かないので、customSearch内で何か(例えばjqueryの関数の実行など)を行っている場合、実行されません。その場合、resultCompleteだと動くのでこちらを利用しましょう。

MovableTypeのDataAPIを断念した理由

  • 検索速度が遅い
  • キーワード検索したときに、記事のカテゴリが取得できない
  • 1回のリクエストで複数カテゴリを指定して記事を取得できない

実現はできるが、遅いというのが気になった。

参考

flexible Search
便利なライブラリありがとうございます。

20
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
21