WEB制作、マーケティングに関する情報をお届けします。ホームページ制作会社、テラのブログ

WordPressでの検索対象を固定ページ、投稿ページ、カスタム投稿、カスタムフィールドなどで絞り込む方法

タグ:

WordPressでの検索する際にはデフォルトでは固定ページ、投稿ページ、カスタム投稿ページの全てが対象になります。
サイトを構築するうえではこの中から除外したいものが出てくるケースは多いでしょう。
コーポレートサイト、お知らせ、コラムなどを持つ場合は、検索結果から固定ページを除外するということがよくあります。
また、オウンドメディアなどのサイトではカスタムフィールド内も検索対象としたい場合もあるでしょう。

今回は『Wordpressでの検索対象を固定ページ、投稿ページ、カスタム投稿、カスタムフィールドなどで絞り込む方法』を紹介します。

コードの紹介

検索フォーム

テンプレートに直書きしてもいいですし、『searchform.php』を作成してテンプレートで読み込んでもどちらでも構いません。

<form role="search" method="get" action="<?php echo home_url() ?>" >
    <div class="s-box">
        <input type="hidden" value="post">
        <input type="text" value="" name="s" placeholder="キーワードで検索">
        <button type="submit" value="">検索</button>
    </div>
</form>

絞り込みの機能

functions.phpに記載してください。

/* 検索対象を絞り込み */
function custom_search_with_conditions($search, $wp_query)
{
    global $wpdb;
    if (!$wp_query->is_search) return $search;
    if (!isset($wp_query->query_vars)) return $search;

    // 設定された変数を使用
    $post_type_array = array('post','page'); // 検索対象としたい投稿種別を指定
    $post_name_array = array('custom_post_a','custom_post_b'); // カスタム投稿タイプのスラッグ名
    $custom_field_array = array('custom_field_a', 'custom_field_b','custom_field_c'); // 検索対象にしたいカスタムフィールド
    $taxonomy_array = array('taxonomy_a','taxonomy_b'); // カスタムタクソノミーのスラッグ名
    
    // 検索語句を取得
    $search_words = explode(' ', mb_convert_kana( isset($wp_query->query_vars['s']) ? $wp_query->query_vars['s'] : '') );

    if (count($search_words) > 0) {
        $search = '';

        foreach ($search_words as $word) {
            if (!empty($word)) {
                $search_word = '%' . esc_sql($word) . '%';
                $search .= " AND (
                    {$wpdb->posts}.post_title LIKE '{$search_word}' -- タイトル
                    OR {$wpdb->posts}.post_content LIKE '{$search_word}' -- コンテンツ
                    OR {$wpdb->posts}.post_name LIKE '{$search_word}'";

                // カスタムフィールドの条件を追加
                if (!empty($custom_field_array)) {
                    foreach ($custom_field_array as $custom_field) {
                        $search .= " OR {$wpdb->posts}.ID IN (
                            SELECT DISTINCT post_id
                            FROM {$wpdb->postmeta}
                            WHERE meta_key = '" . esc_sql($custom_field) . "' AND meta_value LIKE '{$search_word}'
                        )";
                    }
                }
                // タクソノミーの条件を追加
                if (isset($taxonomy_array) && !empty($taxonomy_array)) {
                    foreach ($taxonomy_array as $taxonomy) {
                        $search .= " OR {$wpdb->posts}.ID IN (
                            SELECT DISTINCT r.object_id
                            FROM {$wpdb->term_relationships} AS r
                            INNER JOIN {$wpdb->term_taxonomy} AS tt ON r.term_taxonomy_id = tt.term_taxonomy_id
                            INNER JOIN {$wpdb->terms} AS t ON tt.term_id = t.term_id
                            WHERE t.name LIKE '{$search_word}' AND tt.taxonomy = '" . esc_sql($taxonomy) . "'
                        )";
                    }
                }

                $search .= ")"; // メイン検索条件の終了
            }
        }

        // 投稿タイプの条件を追加
        if (!empty($post_type_array) || !empty($post_name_array)) {
            $search .= " AND (";

            if (!empty($post_type_array)) {
                $post_types = implode("','", esc_sql($post_type_array));
                $search .= "{$wpdb->posts}.post_type IN ('{$post_types}')";
            }

            if (!empty($post_name_array)) {
                if (!empty($post_type_array)) {
                    $search .= " OR ";
                }

                foreach ($post_name_array as $index => $post_name) {
                    if ($index > 0) {
                        $search .= " OR ";
                    }
                    $search .= "{$wpdb->posts}.post_type = '" . esc_sql($post_name) . "'";
                }
            }

            $search .= ")";
        } else {
            // 取得済みのカスタム投稿タイプを NOT IN に追加しないようにする
            $excluded_types = array('post', 'page');
            $custom_post_types = get_post_types(array('_builtin' => false), 'names');

            if (!empty($custom_post_types)) {
                foreach ($custom_post_types as $custom_post_type) {
                    if (!in_array($custom_post_type, $post_name_array)) {
                        $excluded_types[] = esc_sql($custom_post_type);
                    }
                }
            }

            $excluded_types_list = implode("','", $excluded_types);
            $search .= " AND {$wpdb->posts}.post_type NOT IN ('{$excluded_types_list}')";
        }
    }

    return $search;
}
add_filter('posts_search', 'custom_search_with_conditions', 10, 2);

検索結果ページ

『search.php』などに記載するものです。
ループを設置するだけです。

<?php get_header() ?>

<ul>
<?php
if(have_posts()):
   while(have_posts()):the_post();
?>
    <li class="fle_btw">
        <a href="">
        <?php the_title() ?>
        </a>
    </li>
<?php endwhile; ?>
<?php else: ?>
検索結果がありません
<?php endif; ?>
</ul>
<?php $post_no = get_option('posts_per_page');
    $newsPost_no = wp_count_posts();
    $newsPost_pub_no = $newsPost_no->publish;
?>
<?php if( $newsPost_pub_no > $post_no ):?>
<div class="pagination">
<?php
echo paginate_links( array(
'format' => '?paged=%#%',
'current' => max( 1, get_query_var('paged') ),
'prev_text' => '<i class="fa fa-angle-left"></i>',
'next_text' => '<i class="fa fa-angle-right"></i>'
) );
?>
</div>
<?php endif; ?>

<?php wp_reset_postdata(); ?>

<?php get_footer() ?>

コードを解説

入力フォーム(searchform.phpなど)、検索結果ページ(search.phpなど)は特に変わったものはありませんので説明を割愛します。
functions.phpに記載する内容だけ解説します。
以下で関数を作成します。

function custom_search_with_conditions($search, $wp_query){}

『$wpdb』を使用してデータベースを操作していきます。

global $wpdb;

検索結果ページ以外だったら処理を終了させます。

if (!$wp_query->is_search) return $search;
if (!isset($wp_query->query_vars)) return $search;

条件の指定をしていきます。
上から投稿種別、カスタム投稿タイプのスラッグ、カスタムフィールドのフィールド名、カスタムタクソノミーのスラッグを配列で入れます。ここに記載したものが検索結果への対象となります。コピペで使う場合はここを必要に応じて編集することで簡単に絞り込みできるようになります。

$post_type_array = array('post','page'); // 検索対象としたい投稿種別を指定
$post_name_array = array('custom_post_a','custom_post_b'); // カスタム投稿タイプのスラッグ名
$custom_field_array = array('custom_field_a', 'custom_field_b','custom_field_c'); // 検索対象にしたいカスタムフィールド
$taxonomy_array = array('taxonomy_a','taxonomy_b'); // カスタムタクソノミーのスラッグ名

検索結果の処理部分を書いていきます。まずは検索キーワードを取得してキーワードごとを配列に変えます。
『isset($wp_query->query_vars[‘s’]) ? $wp_query->query_vars[‘s’] : ”』の部分は三項演算です。『isset($wp_query->query_vars[‘s’])』で検索キーワードがあるかどうかをチェック、あれば『$wp_query->query_vars[‘s’]を返します。ない場合は『:(コロン)』の後にあるからの値を返します。さらに『mb_convert_kana』で全角スペースを半角スペースに変換します。
『explode()』で半角スペースごとにキーワードを配列に入れていきます。

$search_words = explode(' ', mb_convert_kana( isset($wp_query->query_vars['s']) ? $wp_query->query_vars['s'] : '') );

検索キーワードの入力値があるかをチェック、あった場合に処理を行います。

if (count($search_words) > 0) { }

DBへのリクエストに使用する内容を保存しておくためにあらかじめ『$search』の変数を作成しておきます。

$search = '';

配列を一つずつ取り出してasでループさせてDBに命令するためのSQL文を『$search .=』で文字列として追加していきます。

foreach ($search_words as $word) {
    if (!empty($word)) {
        $search_word = '%' . esc_sql($word) . '%';
        $search .= " AND (
            {$wpdb->posts}.post_title LIKE '{$search_word}' -- タイトル
            OR {$wpdb->posts}.post_content LIKE '{$search_word}' -- コンテンツ
            OR {$wpdb->posts}.post_name LIKE '{$search_word}'";

        // カスタムフィールドの条件を追加
        if (!empty($custom_field_array)) {
            foreach ($custom_field_array as $custom_field) {
                $search .= " OR {$wpdb->posts}.ID IN (
                    SELECT DISTINCT post_id
                    FROM {$wpdb->postmeta}
                    WHERE meta_key = '" . esc_sql($custom_field) . "' AND meta_value LIKE '{$search_word}'
                )";
            }
        }
        // タクソノミーの条件を追加
        if (isset($taxonomy_array) && !empty($taxonomy_array)) {
            foreach ($taxonomy_array as $taxonomy) {
                $search .= " OR {$wpdb->posts}.ID IN (
                    SELECT DISTINCT r.object_id
                    FROM {$wpdb->term_relationships} AS r
                    INNER JOIN {$wpdb->term_taxonomy} AS tt ON r.term_taxonomy_id = tt.term_taxonomy_id
                    INNER JOIN {$wpdb->terms} AS t ON tt.term_id = t.term_id
                    WHERE t.name LIKE '{$search_word}' AND tt.taxonomy = '" . esc_sql($taxonomy) . "'
                )";
            }
        }

        $search .= ")"; // メイン検索条件の終了
    }
}

対象となる投稿タイプを追加します。
また、取得したカスタム投稿タイプがNOT INで追加されないようにします。

// 投稿タイプの条件を追加
if (!empty($post_type_array) || !empty($post_name_array)) {
    $search .= " AND (";

    if (!empty($post_type_array)) {
        $post_types = implode("','", esc_sql($post_type_array));
        $search .= "{$wpdb->posts}.post_type IN ('{$post_types}')";
    }

    if (!empty($post_name_array)) {
        if (!empty($post_type_array)) {
            $search .= " OR ";
        }

        foreach ($post_name_array as $index => $post_name) {
            if ($index > 0) {
                $search .= " OR ";
            }
            $search .= "{$wpdb->posts}.post_type = '" . esc_sql($post_name) . "'";
        }
    }

    $search .= ")";
} else {
    // 取得済みのカスタム投稿タイプを NOT IN に追加しないようにする
    $excluded_types = array('post', 'page');
    $custom_post_types = get_post_types(array('_builtin' => false), 'names');

    if (!empty($custom_post_types)) {
        foreach ($custom_post_types as $custom_post_type) {
            if (!in_array($custom_post_type, $post_name_array)) {
                $excluded_types[] = esc_sql($custom_post_type);
            }
        }
    }

    $excluded_types_list = implode("','", $excluded_types);
    $search .= " AND {$wpdb->posts}.post_type NOT IN ('{$excluded_types_list}')";
}

最後に結果を『return $search;』で返します。

まとめ

以上、『Wordpressでの検索対象を固定ページ、投稿ページ、カスタム投稿、カスタムフィールドなどで絞り込む方法』でした。
検索条件の絞り込みは頻繁に必要となるケースですので、躓いた場合はぜひ、参考にしてください。

テラ合同会社(東京都)

テラは2014年に東京都でスタートアップしたホームページ制作会社です。ホームページ制作以外にも広告運用、マーケティング、ブランディング、印刷物など幅広い領域をサポートしています。
コーポレートサイトはこちらをご覧ください。