suumoの様な不動産サイトを WorePressで作る方法!
連載:WPでsuumoの様な不動産サイトを作る

WPで作った不動産サイトに絞込検索機能をつける

今回は「suumoの様な不動産サイトを作る」の連載3回目、「WPで作った不動産サイトに絞込検索機能をつける」今回は技術的にも知識的にも中々高度な内容となっています。
いじっているファイルは、前回作った『rent.php』と『function.php』のみですが、WPのクエリやフックのタイミング等の知識が無いと中々難しい内容です。
今回は「suumoの様な不動産サイトを作る」の連載3回目、「WPで作った不動産サイトに絞込検索機能をつける」です。今回は技術的にも知識的にも中々高度な内容となっています。
いじっているファイルは、前回作った『archive-rent.php』と『function.php』のみですが、WPのクエリやフックのタイミング等の知識が無いと中々難しい内容です。

私としても、今回は提案というか、こういう形で実装できますがいかがでしょうか的な、、、
もっと簡単でわかりやすいやり方があったら教えて欲しい的な、、、
この作りだとこういう場合やばくなりませんか?ってなことを教えて欲しい的な、、、
感じで記事を書かせていただきました。

この記事に対抗して、こうやったらいいんでないのっていう感じの記事をどこかで書いてくれる人を募集中です(汗
是非最高の絞り込み検索の導入方法を作って行きたいですね。

まあとりあえず、前回・前々回の連載のとおりに作っていただけていれば、これから書くソースをコピペで絞込検索ができるようになりますので、そんな気持ちで読んでいただければ幸いでございます。

カスタムフィールドを検索に含めるSearch Everythingプラグイン

ソースを見る前に、Search Everythingを入れておいてくだださい。
コレは、検索フォームでテキスト検索をした場合にカスタムフィールドなども検索の対象にしてくれる代物です。

function.phpに検索用の色々を追加

では早速『function.php』に検索用のフックとか関数を追加していきます。
別に『function.php』じゃなくても『function.php』からリクエストでつながってるファイルならいいですよー。
ちょっと長いですが、コピペでOKだと思うんでとりあえず見てみて下さい。

/**
 * 検索機能追加
 *
 */
 
 
//タクソノミーとタームからフォームを作る関数(archive-rent.phpとかから呼び出す関数)
function search_form_html() {
	global $wp_query, $query;
	
	$html = '<form method="post" id="searchform" action="' . home_url( '/' ) . '">';  
	$html .= '<input type="text" name="s"  id="s" value="' . $wp_query->get('s') . '" placeholder="検索したいキーワードを入力してください">';
	$taxonomies = get_taxonomies( array(  //全タクソノミーを配列で取得
		'public'   => true,
		'_builtin' => false
	) );
	foreach( $taxonomies as $taxonomie ) {  //タクソノミー配列を回す
		$html .= '<dl class="search_taxonomie"><dt>' . get_taxonomy($taxonomie)->labels->name . '</dt>';
		$terms = get_terms( $taxonomie, 'hide_empty=0' );   //各タクソノミーのタームを取得
		if ( ! empty( $terms ) && !is_wp_error( $terms ) ){
			foreach ( $terms as $key => $term ) {  //各タームを回して
				$html .= '<dd><input type="checkbox" name="' . $term->taxonomy . '[]" value="' . $term->slug . '">' . $term->name . '</dd>';  //インプットを作成
			}
			$html .= '</dl>';
		}
	}
	$html .= '<input type="submit" class="searchsubmit" value="検索する">';
	$html .= '</form>';
	
	echo $html;  //作成したフォームを返す
}


// カスタムクエリ追加
function myQueryVars( $public_query_vars ) {
	$taxonomies = get_taxonomies( array(  //前回作ったタクソノミーを取得
	'public'   => true,
	'_builtin' => false
	) );
	foreach ( $taxonomies as $taxonomie ) {  //それを回す
		$public_query_vars[] = $taxonomie;  //カスタムクエリを既存のクエリに追加
	}
	return $public_query_vars;
}
add_filter( 'query_vars', 'myQueryVars' );  //SQL が生成される前に、WordPress のパブリッククエリ変数のリストに対して適用される。


//?rent=over-30000+over-135000&post_type=rent&key-money-deposit=30000+40000&s= の様なパラメーターを作る
function myRequest( $vars ) {
	$taxonomies = get_taxonomies( array(  //タクソノミー配列取得
		'public'   => true,
		'_builtin' => false
	) );
	foreach( $taxonomies as $taxonomie ) {  //タクソノミー配列回す
		$terms = get_terms( $taxonomie, 'hide_empty=0' );  //タームオブジェクト取得
		if ( ! empty( $terms ) && !is_wp_error( $terms ) ){
			foreach ( $terms as $key => $term ) {  //タームオブジェクト回す
				if ( !empty( $vars[$term->taxonomy] ) && is_array( $vars[$term->taxonomy] ) ) {  //クエリに選択したタクソノミーが含まれていたら 
					$vars[$term->taxonomy] = implode( '+', $vars[$term->taxonomy] );  //プラスで連結してクエリに入れる
				}
			}
		}
	}
	if ( isset( $_POST['s'] ) && !empty( $vars ) ) {  //検索フォームから来ていて、クエリからじゃなかったら
		$url = home_url('/rent/') . "?";
		$gets = array();
		foreach( $vars as $key => $val ) {
			if ($key == 's') {
				$val = str_replace('&', '%26', $val);  //文字化けとかしないようにして
			}
			if ( strlen( $val ) > 0 ) {
				if ( mb_detect_encoding( $val ) !== 'ASCII' ) {  //しないようにして
					$val = urlencode( $val );
				}
				$gets[] = "{$key}={$val}";  
			}
		}
		if ( empty( $vars['s'] ) ) {
			$gets[] = "s=";
		}
		wp_redirect( $url . implode( '&', $gets ) );  //?rent=over-30000+over-135000&s=みたいにして/rent/にリダイレクト
		exit;
	}
	return $vars;
}
add_filter( 'request', 'myRequest');  //追加クエリ変数・プライベートクエリ変数が追加された後に適用される。


//パラメーターを元にtax_queryを作る
function myFilter( $query ) {
	global $wp_query;
	
	if ( !array_key_exists( 's', $query->query ) ) { //詳細ページの場合
		return $query;  //そのまま表示
	} else {
		if ( $query->get('name') ) {  //違ったらnameをクエリから取り除く
			unset($wp_query->query['name']);
		}
	}

	if ( $query->get( 'post_type' ) === 'rent') {
		if ( count( $wp_query->query ) === 1 ) return $query;
		$args = $wp_query->query;
		$meta_query = array();
		$tax_query = array();
		
		$taxonomies = get_taxonomies( array(
			'public'   => true,
			'_builtin' => false
		) );
		
		//tax_queryを作っていく
		foreach( $taxonomies as $taxonomie ) {
			$terms = get_terms( $taxonomie, 'hide_empty=0' );
			if ( ! empty( $terms ) && !is_wp_error( $terms ) ){
				foreach ( $terms as $key => $term ) {
					
					if ( array_key_exists( $taxonomie, $wp_query->query ) ) {
						
						$slug = $query->get('rent');
						
						$slug = $query->get($taxonomie);
						$slug = explode( '+', $slug );
						$tax_query[] = array(
							'taxonomy' => $taxonomie,
							'field' => 'slug',
							'terms' => $slug,
							'operator' => 'IN',
						);
						unset($args[$taxonomie]);
						break ;
					}
					
				}
			}
		}
		//クエリを作りなおしたら
		$args['meta_query'] = $meta_query;
		$args['tax_query'] = $tax_query;
		
		//古いの消して
		$query->init();
		$query->parse_query( $args );  //新しいクエリにする
		$query->is_search = true;      //検索ページだよってことにする
		
	}
	return $query;
}
add_filter('pre_get_posts','myFilter');  //クエリを実行する前に呼び出し

今回3つのフックを使用しましたが呼び出す順番は上から順に、『query_vars』『request』『pre_get_posts』の順に動いていきます。
ちょっと僕も上手く説明すれと言われても説明できない感じでしてねー・・・
簡単に説明は書いたんで、とりあえず参考にはなると思います。

コレで前回と前々回のようにタクソノミーとか作っていってくれていれば動くはずです。
次に『archive-rent.php』のソースを書いていきます。

archive-rent.phpを検索用にカスタマイズ

では次に前回作った『archive-rent.php』を検索用にカスタマイズしていきます。
早速ソースを見てみてください。
(テーマの余計な部分は削除しています)

<?php
get_header(); ?>

	<section id="primary" class="content-area">
		<main id="main" class="site-main" role="main">

		<?php //if ( have_posts() ) :  //これは消す  ?>

			<header class="page-header">
				<h1 class="page-title">物件検索</h1>
			</header><!-- .page-header -->
			
			<?php
			
			if ( !is_search() ) {  //検索後じゃない時
				search_form_html();  //フォームを呼び出す
			} else {               //検索した時
				if ( ! $wp_query->found_posts ) {         //結果が無いとき
					echo '条件にあうものはないです';
				} else {                                   //結果があるときは結果を普通にループ
					while ( have_posts() ) : the_post(); ?>
				<article class="archive-rent_article">
					<div class="lr">
						<div class="lr_l">
							<?php the_post_thumbnail( 'full' );  ?>
						</div>
						<div class="lr_r">
							<div class="type"><?php the_field ( "Building Type" ); ?></div>
							<h2 class="renttitle"><?php the_title() ?></h2>
							<div class="place">
								<ul>
									<li><?php the_field ( "Street address" ); ?></li>
									<?php
									if ( have_rows ( 'Nearest station' ) ) :
										echo '<li>';
										while ( have_rows ( 'Nearest station' ) ) : the_row();
											echo '<div id="station">';
											echo get_sub_field( 'station' );
											echo '</div>';
										endwhile;
										echo '</li>';
									endif;
									?>
									<li>
									<div><?php the_field ( "Age" ); ?></div>
									<div><?php the_field ( "Building Type" ); ?></div>
									</li>
								</ul>
							</div>
						</div>
					</div>
					<table class="detail">
						<tr>
							<th>階</th>
							<th>賃料</th>
							<th>管理費</th>
							<th>敷/礼/保証/敷引,償却</th>
							<th>間取り</th>
							<th>専有面積</th>
							<th></th>
						</tr>
						<tr>
							<td><?php the_field ( "Story2" ); ?></td>
							<td class="rentrent"><?php the_field ( "rent" ); ?></td>
							<td><?php the_field ( "Administrative" ); ?></td>
							<td><?php the_field ( "Deposit" ); ?>/<?php the_field ( "deposit2" ); ?>/<?php the_field ( "deposit3" ); ?>/<?php the_field ( "Amortization" ); ?></td>
							<td><?php the_field ( "Floor plan" ); ?></td>
							<td><?php the_field ( "Occupied area" ); ?></td>
							<td><a href="<?php the_permalink(); ?>" class="rent_detail">詳細を見る</a></td>
						</tr>
					</table>
				</article>
			<?php endwhile;
				}
			}
		
		?>

		<?php //endif; //これも消す  ?>

		</main><!-- #main -->
	</section><!-- #primary -->

<?php get_footer(); ?>

とまあ、こんな感じですよね~…
よくわかんないですよね?…
とりあえず、フォームから送られてきた情報からクエリを作って、検索した内容がなければ「無いです」と表示して、ある場合はクエリのとおりにループ。
そもそも検索じゃなかった時は検索フォームを出しています。
すみません上手く説明ができませんので、参考に色々やってみてください。

第三回まとめ

ちょっと今回は異常に投げっぱなしになってしまいましたねー…
ある程度高度な内容になってきているので、説明が難しくて(言い訳)

本当は一覧のサイドカラムにフォームを設置したり、現在の検索条件を表示したりまでをご説明をしようと思ってたのですが、やってみたら意外と時間がかかってしまって、ココらへんが限界です。。。

ただ、参考にはなると思います。この通りやれば絞り込み検索は使えますので、ソースをよく読んで調べて、カスタマイズしてみてくださいね。

著者