【WordPress】カスタムフィールドを使って投稿の絞り込み検索を実装する

2024年5月15日

投稿の絞り込み検索は様々な用途があり、ブログ訪問者の利便性を高める一つの機能でもあります。

・・・ということの一環として。

カスタム投稿をカスタムフィールドの値で絞り込み検索できると便利です。

なので、投稿データを取得して表示するWP_Queryで絞り込み検索を実装することに。

投稿データを利用した絞り込み検索にも応用できます。

's’という便利なやつ

絞り込み検索というと、キーワード検索が主な機能だとは思います。

ワードプレスで記事検索用の便利機能で「s」があります。

HTMLフォームのname属性を"s"とすると、検索結果テンプレートを呼び出して、検索結果として表示してくれます。

とても便利!・・・なんですが。

表示を抑制する場合にカスタム投稿用の検索結果テンプレートのsearch-{カスタム投稿名}.phpを用意しなければならなかったり。

検索結果だけどカスタムフィールドの値をテーブルで表示したいだけだったり。

そこまでしっかりしたものじゃなくても・・・という時が個人的に多いです。

デフォルトテンプレートで条件分岐書くのもあれなので、1枚のPHPで済ませる方向で作成します。

大まかな流れ

ということで、順番に行きたいと思いますが。

ざっくりと流れを書くと。

カスタム投稿に含まれるカスタムフィールドの値を一覧表示する

カスタムフィールドの値で絞り込む

該当するカスタムフィールドの値を持つカスタム投稿のカスタムフィールドの値だけ表示する

という動作です。・・・カスタムカスタムで読みにくかったらすみません。

なので、まずは投稿記事一覧を表示します。

投稿記事一覧

WP_Queryを利用してサブループで実行します。

<?php
//基本的なパラメータだけにしておく
$args = array(
    'no_found_rows' => true,
    'post_type' => 'test_posts',
    'post_publish' => 'publish',
    'orderby' => 'ID',
    'posts_per_page' => -1,
);

$test_posts = new WP_Query( $args );

if( $test_posts->have_posts() ):
 while($test_posts->have_posts() ) : $test_posts->the_post();
?>

<h2><?php echo the_title; ?></h2>
<div><?php echo get_post_meta( get_the_ID(), 'test_field_value', true ); ?></div>

<?php
endwhile;
endif;
wp_reset_postdata();
?>

カスタム投稿タイプ’test_posts’の投稿タイトルとカスタムフィールド’test_field_value’の値を全件表示します。

ページネーションを使う場合は’posts_per_page’で表示したい投稿数を指定してください。

ここでのポイント・・・という程でもないですが、クエリの指定は投稿内の全記事を取得するだけにとどめておくことでしょうか。

どんなに考えても結局は絞り込みしてもらうことが目的なので。

もちろん、データ量(投稿数)にもよりますが。

絞り込むためのフォームを作る

絞り込み検索で使用するフォームを作ります。

せっかくなので一つ前の記事で書いた、カスタムフィールドの値で作成したセレクトボックスを使います。

<?php
//パラメータはWP_Queryと同じものを使用
$test_select_values = get_posts( $args );
?>
<div>
    <form method="post" action="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; ?>">
    <label for="test_post_values">セレクトボックス</label>
      <select name="test_post_values">
        <option value="" >選択</option>
          <?php
                    //配列の値をセレクトボックスの要素に
            foreach( $test_select_values as $value ){
               if( $value === $search_value ){
                echo '<option value="' . $value . '"checked>' . $value . '</option>';
               }else{
                echo '<option value="' . $value . '">' . $value . '</option>';
               }
            }
          ?>
      </select>
    </form>
</div>
<?php
wp_reset_postdata();
?>

検索値として使用するセレクトボックスの値は、絞り込みの影響を受けないように別のサブループを使用します。

ただ、取得するのはWP_Queryで使用するものと同じなので、パラメータは同じものを使用します。

配列の整理が必要であれば、array_unique()やarray_filter()を使いましょう。

フォーム要素ではaction属性にサーバー変数を使用して、同じページに選択した値を渡して表示するようにしています。

セレクトボックスも選択された値が保持されるようにif文を。

これでフォーム部分はOKです。

最後に全文載せますが、コードの挿入位置はWP_Queryにパラメータを渡す「new WP_Query( $arg )」の前に。

絞り込み機能を作る

次にフォームから渡された値を受け取り、その値でクエリの内容が変わるようにします。

<?php
//セレクトボックスの選択値の受け取り
$search_value = filter_input( INPUT_POST, 'test_post_values' );

//クエリに追加する内容
if( !empty( $search_value ) ){
    $args += array(
        'meta_value' => $search_value,
        'meta_key' => 'test_field_value',
    );
}

フォームをpostで送信したので、filter_input()もポストで受け取ります。

そして、絞り込みに使用する選択値がある時に、クエリのパラメータを追加します。

検索する値は選択値で、探す場所は’test_field_value’というカスタムフィールド、という指示です。

同じ投稿に含まれる別のカスタムフィールドも同じ選択値で検索することもできます。

//複数のカスタムフィールドから検索
if( !empty( $search_value ) ){
    $args += array(
        'meta_value' => $search_value,
        'meta_query' => array(
            'relation' => 'OR',
            array( 'key' => 'test_field_value1' ),
            array( 'key' => 'test_field_value2' ),
            array( 'key' => 'test_field_value3' ),
        ),
    );
}

前のは単一のカスタムフィールドからの検索だったので’meta_key’で指定しましたが。

カスタムフィールドのパラメータ’meta_query’を使用することで、複数のカスタムフィールドの検索も可能となります。

値の検索値もそれぞれ変える場合は、’meta_value’の行を削除して’meta_query’の各カスタムフィールドを指定している配列の中に、’value’を指定することで可能です。

・・・これは近いうちにもう一度書くかもしれません。

コード全文

<?php
//セレクトボックスの選択値の受け取り
$search_value = filter_input( INPUT_POST, 'test_post_values' );

//基本的なパラメータだけにしておく
$args = array(
    'no_found_rows' => true,
    'post_type' => 'test_posts',
    'post_publish' => 'publish',
    'orderby' => 'ID',
    'posts_per_page' => -1,
);

//絞り込み検索のセレクトボックスの作成
$test_select_values = get_posts( $args );
?>
<div>
    <form method="post" action="<?php echo 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; ?>">
    <label for="test_post_values">セレクトボックス</label>
      <select name="test_post_values">
        <option value="" >選択</option>
          <?php
                    //配列の値をセレクトボックスの要素に
            foreach( $test_select_values as $value ){
               if( $value === $search_value ){
                echo '<option value="' . $value . '"checked>' . $value . '</option>';
               }else{
                echo '<option value="' . $value . '">' . $value . '</option>';
               }
            }
          ?>
      </select>
    </form>
</div>
<?php
wp_reset_postdata();

//クエリに追加する内容
if( !empty( $search_value ) ){
    $args += array(
        'meta_value' => $search_value,
        'meta_key' => 'test_field_value',
    );
}

//選択値がなければ一覧表示、あれば絞り込み表示
$test_posts = new WP_Query( $args );

if( $test_posts->have_posts() ):
 while($test_posts->have_posts() ) : $test_posts->the_post();
?>

<h2><?php echo the_title; ?></h2>
<div><?php echo get_post_meta( get_the_ID(), 'test_field_value', true ); ?></div>

<?php
endwhile;
endif;
wp_reset_postdata();
?>

投稿データを色々と扱えると便利

投稿を一つのデータとして捉えると、ワードプレスの投稿にもブログ記事以外の用途が見えてきます。

もちろん、元々がブログなので向き不向きはありますが。

投稿の全データはいらないけど、カスタムフィールドを一覧表示したいという時に書いたコードでした。

参考:サイト内検索の仕組みとURLに付けるパラメータ‐コトダマウェブ
参考:class WP_Query {}‐Wordpress.org