Skip to content

Instantly share code, notes, and snippets.

@SapporoTK
Last active February 22, 2017 02:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SapporoTK/724ec1341f82435242fb4c9f47135b23 to your computer and use it in GitHub Desktop.
Save SapporoTK/724ec1341f82435242fb4c9f47135b23 to your computer and use it in GitHub Desktop.
WordPress + Custom Fields に複雑な検索機能を実装する。/reference http://www.deluxeblogtips.com/2012/04/search-all-custom-fields.html
global $wpdb;
//次のSQLに SQL_CACHE を含めているのは、レンタルサーバーによってはMySQLのクエリキャッシュの
//デフォルト設定を無効にしているところがあるので、明示的にクエリキャッシュを有効にするように指定している。
$sql = "SELECT SQL_CACHE DISTINCT posts.ID FROM {$wpdb->posts} posts";
//チェックボックスorセレクトボックスの検索(複数のAND検索)
//例えばcolorというフィールド名だとする。
//$_GET['color']にはカスタムフィールドの設定画面の選択肢の箇所で入力したラベルと値のうち、値の方が配列になって入ってくるとする。
if( count($_GET['color']) )
{
$flg_query = true;
$sql .= " INNER JOIN {$wpdb->postmeta} tbl_color ON tbl_color.post_id=posts.ID AND tbl_color.meta_key = 'color'";
$tmp_arr = array();
foreach ($_GET['color'] as $item)
{
//シリアライズ化された文字列の中を全文検索する
$keyword = '%' . $wpdb->esc_like( '"' . trim($item) . '"' ) . '%';
$tmp_arr[] = "tbl_color.meta_value LIKE '{$keyword}'";
}
$sql .= " AND (" . implode(" AND ", $tmp_arr) . ") ";
//↓ちなみにOR検索の場合はこうする
//$sql .= " AND (" . implode(" OR ", $tmp_arr) . ") ";
}
//複数のチェックボックスorセレクトボックスがある場合は、ここに追記していく。
//注意点として、選択肢の値を 1,2,3・・や a,b,c・・のように設定すると
//他のフィールドと値が重複して正確な検索が出来ないので、全フィールドを通じてユニークな値にする必要がある。
$sql .= " WHERE posts.post_type='(※投稿タイプ名※)' AND posts.post_status='publish'";
//全文検索(AND検索)
//全文検索用キーワード
//$_GET['keyword']にはキーワードが半角スペース区切りで入っているとする。
$free_keyword = isset($_GET['keyword']) ? trim($_GET['keyword']) : ""; //「キーワード検索」
if( $free_keyword != "" )
{
$arr_free_keyword = $free_keyword == "" ? array() : explode(" ", $free_keyword);
$arr_free_keyword = array_unique($arr_free_keyword);
if( count($arr_free_keyword) > 8 )
{
//検索キーワード数の上限をとりあえず8個までにする。
//ここが無制限だと、意図的に膨大なキーワード数で検索を実行された時にサーバーの処理が追いつかなくなる危険性が生じるので。
$arr_free_keyword = array_slice($arr_free_keyword, 0, 8);
}
$tbl_cnt = 1;
foreach ($arr_free_keyword as $_key)
{
$tbl = "key" . $tbl_cnt++;
$keyword = '%' . $wpdb->esc_like( trim($_key) ) . '%';
$sql .= " AND (SELECT 1 FROM {$wpdb->postmeta} {$tbl} WHERE {$tbl}.post_id=posts.ID AND ( ({$tbl}.meta_key NOT LIKE '\_%' AND {$tbl}.meta_value LIKE '{$keyword}') OR posts.post_title LIKE '{$keyword}' OR posts.post_content LIKE '{$keyword}') LIMIT 1)";
//↑DISTINCTにしてもいいのだが、LIMIT 1 の方が速度が早いと思われるので(ただし未検証)
}
}
$post_ids = $wpdb->get_col($sql); //検索でヒットした投稿データのIDが入る
$cnt = count($post_ids); //投稿数
if($cnt)
{
$args = array(
'post_type' => '(※投稿タイプ名※)',
'post_status' => 'publish',
'post__in' => $post_ids,
//ページングする場合は次のパラメーターをお好みで
'posts_per_page' => ****,
'offset' => ***,
//ソートする場合は 次のパラメーターをお好みで
'meta_key' => '******',
'order' => "ASC", /* or DESC */
'orderby' => "meta_value"
);
$posts = get_posts($args);
}
else
{
$posts = array();
}
以下略
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment