concrete5の検索ブロックを複合検索にカスタマイズする
Posted by admin at 12:02 日時 2013/04/09
concrete5のデフォルトの検索ブロックは、実はページ属性を使った複合検索に対応しています。ブログのタグ検索に対応するためですね。
そんなわけで、検索ブロックのカスタムテンプレートを作成し、属性を追加してあげるだけでOKです。楽ちん。検索ブロックのデフォルトテンプレートは
/concrete/blocks/search/view.php
です。このファイルを複製し、
/blocks/search/templates/custom_search.php
にコピーします。そして、中身に下記のように追記します。
<?php defined('C5_EXECUTE') or die("Access Denied."); ?> <?php if (isset($error)) { ?> <?php echo $error?><br/><br/> <?php } ?> <form action="<?php echo $this->url( $resultTargetURL )?>" method="get" class="ccm-search-block-form"> <?php if( strlen($title)>0){ ?><h3><?php echo $title?></h3><?php } ?> <?php if(strlen($query)==0){ ?> <input name="search_paths[]" type="hidden" value="<?php echo htmlentities($baseSearchPath, ENT_COMPAT, APP_CHARSET) ?>" /> <?php } else if (is_array($_REQUEST['search_paths'])) { foreach($_REQUEST['search_paths'] as $search_path){ ?> <input name="search_paths[]" type="hidden" value="<?php echo htmlentities($search_path, ENT_COMPAT, APP_CHARSET) ?>" /> <?php } } ?> <input name="query" type="text" value="<?php echo htmlentities($query, ENT_COMPAT, APP_CHARSET)?>" class="ccm-search-block-text" /> <?php /* ここから追加 */ ?> <h4>タグで絞り込み</h4> <div> <?php Loader::model('attribute/categories/collection'); $ak = CollectionAttributeKey::getByHandle('tags'); $ak->render('search'); ?> </div> <h4>その他の属性で絞り込み</h4> <div> <?php $ak = CollectionAttributeKey::getByHandle('additional_search'); $ak->render('search'); ?> </div> <?php /* ここまで追加 */ ?> <input name="submit" type="submit" value="<?php echo $buttonText?>" class="ccm-search-block-submit" /> <?php $tt = Loader::helper('text'); if ($do_search) { ...
画面はこのようになります。
ページ属性で設定した値が検索対象になります。
ところで、「タグ」の場合はセレクトボックス、「検索用フィールド」の場合はテキストフィールドなのに、追加したコードはどちらも同じということにお気づきでしょうか。
$ak = CollectionAttributeKey::getByHandle('tags'); $ak->render('search');
タグのところ。
$ak = CollectionAttributeKey::getByHandle('additional_search'); $ak->render('search');
検索用フィールドのところ。getByHandleの値しか違うところがありません。
concrete5の場合は、属性タイプというものがあり、テキストでも真偽値でもセレクトボックスでも日付でも、全て同じコードであとはconcrete5がよろしくやってくれます。なんて便利!
さて、なぜこれだけで複合検索ができるかというと、検索ブロックのコントローラー内の do_search メソッドに色々書かれてます(日本語コメントは筆者)。独自ブロックで実装したい時はここを参考にすればすぐ作れますね。
function do_search() { $q = $_REQUEST['query']; // i have NO idea why we added this in rev 2000. I think I was being stupid. - andrew // $_q = trim(preg_replace('/[^A-Za-z0-9\s\']/i', ' ', $_REQUEST['query'])); $_q = $q; Loader::library('database_indexed_search'); // インデックスページリストを使ってますね。 $ipl = new IndexedPageList(); $aksearch = false; // エイリアスを無視 $ipl->ignoreAliases(); // ここから属性検索 if (is_array($_REQUEST['akID'])) { Loader::model('attribute/categories/collection'); foreach($_REQUEST['akID'] as $akID => $req) { $fak = CollectionAttributeKey::getByID($akID); if (is_object($fak)) { $type = $fak->getAttributeType(); $cnt = $type->getController(); $cnt->setAttributeKey($fak); $cnt->searchForm($ipl); $aksearch = true; } } } // ここから月と年で絞り込んでいます。 if (isset($_REQUEST['month']) && isset($_REQUEST['year'])) { $month = strtotime($_REQUEST['year'] . '-' . $_REQUEST['month'] . '-01'); $month = date('Y-m-', $month); $ipl->filterByPublicDate($month . '%', 'like'); $aksearch = true; } // 検索語や絞り込みがない場合は処理を中断しています。 if (empty($_REQUEST['query']) && $aksearch == false) { return false; } // ここからキーワード検索 $ipl->setSimpleIndexMode(true); if (isset($_REQUEST['query'])) { $ipl->filterByKeywords($_q); } // ここからサイトマップのパスで絞り込み if( is_array($_REQUEST['search_paths']) ){ foreach($_REQUEST['search_paths'] as $path) { if(!strlen($path)) continue; $ipl->filterByPath($path); } } else if ($this->baseSearchPath != '') { $ipl->filterByPath($this->baseSearchPath); } // 検索インデックスから除く設定のページを除外しています。 $ipl->filter(false, '(ak_exclude_search_index = 0 or ak_exclude_search_index is null)'); // 最後にページを取得 $res = $ipl->getPage(); foreach($res as $r) { $results[] = new IndexedSearchResult($r['cID'], $r['cName'], $r['cDescription'], $r['score'], $r['cPath'], $r['content']); } // ビューに値を渡しています $this->set('query', $q); $this->set('paginator', $ipl->getPagination()); $this->set('results', $results); $this->set('do_search', true); $this->set('searchList', $ipl); }
最後に注意点。属性タイプによる検索をするばあいは、検索対象のページには該当のページ属性を必ず設定するようにしてください。値が空であっても、ページ属性自体が設定されていないと、検索対象になりません。