先日、PowerCMS 5で構築を行うサイトにおいてカスタムフィールドを含めたサイト内検索を実装する必要がありました。
PowerCMS 5ではダイナミック検索(AltSearchプラグイン)を利用することでカスタムフィールドを含めた検索が可能になりますが、特定の記事を除外するにはカスタマイズを行う必要がありますので、その方法を紹介します。
カスタムフィールドの作成
今回は記事・ウェブページ両方を除外出来るようにしたかったので、記事・ウェブページにカスタムフィールドを作成します。全ブログで利用する場合はシステムのカスタムフィールドで作成すると良いでしょう。テンプレートタグは任意で構いません。
記事のカスタムフィールド
- システムオブジェクト: 記事
- 名前: サイト内検索から除外
- 種別: チェックボックス
- ベースネーム: entry_exclude_altsearch
ウェブページのカスタムフィールド
- システムオブジェクト: ウェブページ
- 名前: サイト内検索から除外
- 種別: チェックボックス
- ベースネーム: page_exclude_altsearch
プラグインの作成
ダイナミック検索ではコールバックプラグインを作るための仕組みが用意されています。そこで、コールバックプラグインを作成し、上記カスタムフィールドにチェックが入った記事・ウェブページを除外するSQLを追加します。なお、ダイナミック検索ではサーチとカウントで処理が異なるため、二つのコールバックで処理を行う必要があります。
サーチのコールバック
サーチのカスタマイズは pre_altsearch コールバックを利用します。下記PHPコードを記述したファイルを設置します。
/mt/addons/DynamicMTML.pack/php/callbacks/dynamicmtml\_pack\_pre\_altsearch.php
※callbacksディレクトリがない場合は作成してください。
function dynamicmtml_pack_pre_altsearch ( $mt, &$ctx, &$args, &$params ) {
$sql = $params[ 'sql' ];
$offset = $params[ 'offset' ];
$limit = $params[ 'limit' ];
$sort_by = $params[ 'sort_by' ];
$sort_order = $params[ 'sort_order' ];
$_params = array();
$cf_sql = "SELECT entry_meta_entry_id, entry_meta_type, entry_meta_vinteger_idx ";
$cf_sql .= "FROM mt_entry_meta ";
$cf_sql .= "WHERE ((entry_meta_vinteger_idx = 0 AND entry_meta_type = 'field.page_exclude_altsearch') OR (entry_meta_vinteger_idx = 0 AND entry_meta_type = 'field.entry_exclude_altsearch'))";
$match_fld = $ctx->mt->db()->Execute( $cf_sql );
$match_cnt = $match_fld->RecordCount();
if ( $match_cnt ) {
$match_cnt--;
$id_col = "entry_meta_entry_id";
$type_col = "entry_meta_type";
$results = array();
for ( $i = 0; $i <= $match_cnt; $i++ ) {
$match_fld->Move( $i );
$row = $match_fld->FetchRow();
$id = $row[ $id_col ];
$type = $row[ 'entry_meta_type' ];
$type = preg_replace( '/^field\./', '', $type );
$col = $_params[ $type ][ 'column_def' ];
$col = "entry_meta_${col}";
$value = $row[ $col ];
$results[ $id ][ $type ] = $value;
}
}
foreach ( $results as $id => $field_values ) {
$match_all = 1;
foreach ( $_params as $key => $_values ) {
$result = $results[ $id ][ $key ];
if ( !isset( $result ) ) {
$match_all = NULL;
break;
}
}
if ( $match_all ) {
$ids[] = $id;
}
}
$ids = array_unique( $ids );
$ids = join( ',', $ids );
$sql = preg_replace( '/AND/', "AND mt_entry.entry_id in ( ${ids} ) AND", $sql, 1 );
$params = array( 'sql' => $sql, 'sort_by' => $sort_by, 'sort_order' => $sort_order,
'limit' => $limit, 'offset' => $offset );
}
カウントのコールバック
サーチ処理にだけSQLの追加を行うと、検索ヒット件数はカスタマイズを行う前の数になっています。そのためヒット件数にズレが生じて不要なページ送りが出来るなど不都合が生じます。同様にカウントの処理もカスタマイズすることでヒット件数を一致するようにします。
カウントのカスタマイズは pre_altsearch_meta コールバックを利用します。下記PHPコードを記述したファイルを設置します。
/mt/addons/DynamicMTML.pack/php/callbacks/dynamicmtml\_pack\_pre\_altsearch\_meta.php
function dynamicmtml_pack_pre_altsearch_meta ( $mt, &$ctx, &$args, &$sql ) {
$_params = array();
$cf_sql = "SELECT entry_meta_entry_id, entry_meta_type, entry_meta_vinteger_idx ";
$cf_sql .= "FROM mt_entry_meta ";
$cf_sql .= "WHERE ((entry_meta_vinteger_idx = 0 AND entry_meta_type = 'field.page_exclude_altsearch') OR (entry_meta_vinteger_idx = 0 AND entry_meta_type = 'field.entry_exclude_altsearch'))";
$match_fld = $ctx->mt->db()->Execute( $cf_sql );
$match_cnt = $match_fld->RecordCount();
if ( $match_cnt ) {
$match_cnt--;
$id_col = "entry_meta_entry_id";
$type_col = "entry_meta_type";
$results = array();
for ( $i = 0; $i <= $match_cnt; $i++ ) {
$match_fld->Move( $i );
$row = $match_fld->FetchRow();
$id = $row[ $id_col ];
$type = $row[ 'entry_meta_type' ];
$type = preg_replace( '/^field\./', '', $type );
$col = $_params[ $type ][ 'column_def' ];
$col = "entry_meta_${col}";
$value = $row[ $col ];
$results[ $id ][ $type ] = $value;
}
}
foreach ( $results as $id => $field_values ) {
$match_all = 1;
foreach ( $_params as $key => $_values ) {
$result = $results[ $id ][ $key ];
if ( !isset( $result ) ) {
$match_all = NULL;
break;
}
}
if ( $match_all ) {
$ids[] = $id;
}
}
$ids = array_unique( $ids );
$ids = join( ',', $ids );
$sql = preg_replace( '/AND/', "AND entry_id in ( ${ids} ) AND", $sql, 1 );
}
まとめ
以上のプラグインを設置することでダイナミック検索から特定の記事・ウェブページを除外出来るようになります。カスタムフィールドの種別やベースネームが異なる場合は調整が必要になりますが、SQLをカスタマイズすることで標準機能では実現出来ない検索が可能になります。