ワードプレスで企業サイトを制作する場合、店舗情報や求人情報など共通のフォーマットが多ページある場合はカスタムフィールドを使用して処理することがほとんどです。しかし、ワードプレスのキーワード検索機能はこのカスタムフィールドには対応していませんのでPHPとSQLを使用して実装してみます。
2019年3月5日
ワードプレスにはキーワード検索機能が実装されていますが検索対象がタイトルと本文に限られています。プラグインAdvanced Custom Fieldsなどを使用してカスタムフィールドを使用している場合は、その入力内容がキーワード検索の検索対象にはなりません。そこでsearch.phpに手を加えてカスタムフィールドの入力内容を対象にしたキーワード検索を実装してみます。
ワードプレスにはget_search_form()という組み込み関数が用意されていて、以下のような記述で検索フォームを出力できます。
<?php get_search_form(); ?>
■上記で出力されるhtml
<form role="search" method="get" id="searchform" class="searchform" action="http://example.com/">
<div>
<label class="screen-reader-text" for="s">検索:</label>
<input type="text" value="" name="s" id="s" />
<input type="submit" id="searchsubmit" value="検索" />
</div>
</form>
上記のhtmlでもある程度はデザインできますが、ボタンにアイコンを付けたい場合はinputタグではなくbuttonタグを使いたいですし、プレースホルダーなどを設定したい場合もありますので組み込み関数を使わずhtmlで直接フォームを記述します。
<form role="search" method="get" id="searchform" class="searchform" action="http://example.com/">
<div class="hole">
<div class="left">
<label class="screen-reader-text" for="s">キーワード検索</label>
</div>
<div class="right">
<input type="text" value="" name="s" id="s" placeholder="例)年齢不問"/>
<button type="submit" id="searchsubmit"><i class="fa fa-search"></i> 検索</button>
</div>
</div>
</form>
■上記で出力されるキーワード検索フォーム
ワードプレスのデータベースには標準で約12のテーブルがあって、主に_postテーブルが使われています。タイトルと本文だけを対象としたキーワード検索であればこの_postテーブルだけを検索すればいいわけですが、カスタムフィールドを使用した場合はその入力内容は_postmetaテーブルに格納されますので、この2つのテーブルを結合した上で検索することになります。
// _postテーブル
// ID・・・投稿ID
// post_status・・・公開済みの場合はpublish
// post_type・・・カスタム投稿の場合は投稿タイプスラッグ
// post_title・・・投稿タイトル
// post_content・・・投稿本文
//
// _postmetaテーブル
// post_id・・・投稿ID
// meta_key・・・カスタムフィールドのフィールド名
// meta_value・・・カスタムフィールドの入力内容
2つのテーブルを結合して検索するSQL文は以下のようになります。6行目では2つのテーブルをpost_idとIDを共通項として内部結合しています。その上で、post_statusがpublish(公開済み)、post_typeがcareer(ここではカスタム投稿タイプのcareerを指定)、meta_valueに検索ワードを含むレコードを抽出しています。
■search.php
<?php $search_query = get_search_query(); ?>
<?php global $wpdb; ?>
<?php $results =
$wpdb->get_results($wpdb->prepare("
SELECT DISTINCT post_id
FROM $wpdb->postmeta INNER JOIN $wpdb->posts ON post_id = ID
WHERE meta_value LIKE '%s'
AND post_status = 'publish'
AND post_type = 'career'",
"%$search_query%"));
?>
とりあえずこれで該当するレコードを全件抽出することができましたが、次回はこれに少し手を加えて1ページあたり10件表示するためのSQL文にした上でループを回してみたいと思います。
全件抽出することができましたが1ページあたりの表示件数を指定するには1ページあたりの表示件数($per_page)とオフセット($offset)を決めてあげなくてはいけません。オフセットはデータベースからレコードを取り出す際に何件目から取り出すかを指定する値です。
// オフセット
// 1ページ目・・・0
// 2ページ目・・・10
// 3ページ目・・・20
上記を踏まえるとオフセットは以下8行目のような式で値が決まります。
■search.php
<?php
$per_page = 10;
if (preg_match('/^[1-9][0-9]*$/', $_GET['page'])) {
$page = (int)$_GET['page'];
} else {
$page = 1;
}
$offset = $per_page * ($page - 1);
?>
オフセットが決まりましたのでこれを使って前回の全件抽出のSQL文に手を加えてみます。10行目で降順を指定し新しい投稿が先に来るようにしています。11行目でオフセットの値から1ページあたりの表示件数分のレコードを取り出すようにしています。これで1ページでは0番目から10件(0〜9件目まで)、2ページ目では10件目から10件(10〜19件目まで)・・・が抽出されます。
■search.php
<?php $search_query = get_search_query(); ?>
<?php global $wpdb; ?>
<?php $results =
$wpdb->get_results($wpdb->prepare("
SELECT DISTINCT post_id
FROM $wpdb->postmeta INNER JOIN $wpdb->posts ON post_id = ID
WHERE meta_value LIKE '%s'
AND post_status = 'publish'
AND post_type = 'career'
ORDER BY post_modified desc
LIMIT $offset, $per_page",
"%$search_query%"));
?>
あとはforeachを使って1件ずつ取り出し必要なデータを表示していきます。
■search.php
<?php if ($results) : ?>
<ul>
<?php foreach ($results as $result) : ?>
<li>
<a href="<?php echo get_permalink($result->post_id); ?>">
・
・
・
</li>
<?php endforeach; ?>
</ul>
<?php else : ?>
<p><?php echo esc_html('検索条件にヒットした募集はありませんでした。'); ?></p>
<?php endif; ?>
以上で「カスタムフィールドを対象にしたキーワード検索を実装」の解説を終わります。