🔍 「一覧表示をもっと自由にしたい!」そんな時こそフロントUI+WP_Query
「投稿を価格の高い順に並べ替えたい」
「特定のタグやカテゴリだけ絞り込んで表示したい」
──そんなニーズに応えるのが今回のテーマ。
第15回で学んだ WP_Query
のパワーを、今度は ユーザー操作 と連携させて、セレクトボックスやチェックボックスからの絞り込みUIを実装します!
✅ 今回のゴール
- セレクトボックスで並び順を切り替えるUIを作る
- カテゴリや価格帯など、絞り込み条件を連携させて
WP_Query
で反映する - ページリロード(GETパラメータ)による実装で、初心者でもわかりやすい構成に
🧩 実装構成の全体像
- セレクトボックスなどの フォームUI を設置
- フォーム送信時に GETパラメータで条件を渡す
WP_Query
に渡す$args
を、GETパラメータを元に組み立て- 投稿を一覧表示
🧩 実装構成の全体像
📊 データの流れ
[フォームUI]
↓ (GET)
[URLに条件が付加される]
↓
[PHPでGET値を取得]
↓
[WP_Queryの$argsに渡す]
↓
[クエリ実行 → 結果を出力]
💡 フォームから渡されたGET値(例:?sort=asc&cat=5)を使って、
$args
に条件を追加し、WP_Query
で絞り込み表示する流れです。
実装後のUIは、以下のようなセレクトボックスが並んだ構成になります。
📋 完成UIイメージ: ---------------------------- 並び順:[ 価格が安い順 ▼ ] カテゴリ:[ 野菜 ▼ ] 価格帯:[ 〜1,000円 ▼ ] [ 絞り込む ] ----------------------------
このUIから送信された条件を URL に渡し、それを PHP 側で受け取って表示内容を切り替えていきます。
🧪 並び順セレクトボックスの例(価格昇順 / 降順)
▼ HTML側(並び順UI)
<form method="get" class="p-sortForm">
<!-- 並び順のセレクトボックスフォーム。GETメソッドで送信し、URLにパラメータを付加する形式 -->
<label>
並び順:
<select name="sort" onchange="this.form.submit()">
<!-- 初期状態の選択肢 -->
<option value="">選択してください</option>
<!-- 価格が安い順を選んだとき。$_GET['sort'] が 'asc' の場合に selected 属性を付与 -->
<option value="asc" <?php selected($_GET['sort'] ?? '', 'asc'); ?>>価格が安い順</option>
<!-- 価格が高い順を選んだとき。$_GET['sort'] が 'desc' の場合に selected 属性を付与 -->
<option value="desc" <?php selected($_GET['sort'] ?? '', 'desc'); ?>>価格が高い順</option>
</select>
</label>
</form>
📝補足説明(HTML側に記述しないけど知っておくと◎):
selected()
は WordPress のテンプレートタグで、選択肢が選ばれている状態を自動で付けてくれる便利関数です。onchange="this.form.submit()"
によって、選択した瞬間にフォームが送信され、URLに?sort=asc
などのパラメータが付く仕組みです。
🎨 デザインについて: 本記事のHTMLには
.p-sortForm
や.p-filterForm
など、スタイル用のクラス名がついています。 ご自身のサイトのデザインに合わせて、CSSでレイアウトや見た目を調整してくださいね。
🧠 WP_Query 側:GETパラメータで並び順を変える
// 並び順の取得(URLのGETパラメータから取得。未指定時は「asc(価格が安い順)」を初期値に)
$sort_order = $_GET['sort'] ?? 'asc';
// WP_Query 用の引数を設定
$args = [
'post_type' => 'product', // 投稿タイプを「product」に限定(カスタム投稿タイプ)
'posts_per_page' => 6, // 1ページあたり6件表示
'meta_key' => 'price', // 並び替え対象のカスタムフィールド(ACFで定義された価格)
'orderby' => 'meta_value_num', // 数値として並び替え(文字列ではなく数値ソート)
'order' => ($sort_order === 'desc') ? 'DESC' : 'ASC', // GETパラメータが desc なら降順、それ以外は昇順
];
// クエリを実行($query に投稿一覧を格納)
$query = new WP_Query($args);
💡補足ポイント
'meta_value_num'
を使うことで価格の「数値的な並び替え」が可能になります(”10″と”2″が正しく並ぶ)。$_GET['sort'] ?? 'asc'
は「null合体演算子(null coalescing operator)」を使っていて、値が存在しないときの初期値設定に便利です。WP_Query
のインスタンスを$query
に格納しておくことで、ループ内で柔軟に利用できます。
🔁 WP_Query ループの基本構造をおさらい
ここからは、取得した投稿を実際に一覧として出力していきます。
WordPress では have_posts()
~ the_post()
を使って「ループ」を組むのが基本です。
🖥 クエリ結果を出力して一覧表示
<?php if ($query->have_posts()) : ?>
<!-- 投稿が存在する場合はリスト表示 -->
<ul class="p-productList">
<?php while ($query->have_posts()) : $query->the_post(); ?>
<li>
<a href="<?php the_permalink(); ?>">
<!-- 投稿タイトルを表示 -->
<h4><?php the_title(); ?></h4>
<!-- ACFのカスタムフィールド「price」の値を表示 -->
<p>価格:<?php the_field('price'); ?>円</p>
</a>
</li>
<?php endwhile; ?>
</ul>
<!-- クエリで書き換えた投稿データをリセット(次のループやテンプレートに影響しないように) -->
<?php wp_reset_postdata(); ?>
<?php else : ?>
<!-- 該当投稿がなかった場合のメッセージ -->
<p>該当する商品は見つかりませんでした。</p>
<?php endif; ?>
💡補足ポイント
have_posts()
やthe_post()
は WordPress ループの基本関数。the_field('price')
は ACF プラグインを使用している前提です。wp_reset_postdata()
はループ終了後のお作法です。これを忘れると、グローバル変数$post
が壊れて別のテンプレートに影響します。
🔎 複数の絞り込み条件を組み合わせる(カテゴリや価格帯)
▼ UIを拡張
<!-- 絞り込みフォーム(GETメソッドで送信) -->
<form method="get" class="p-filterForm">
<!-- カテゴリー選択フォーム -->
<label>カテゴリー:
<?php
wp_dropdown_categories([
'show_option_all' => 'すべて', // 「すべて」の選択肢を表示(=制限なし)
'name' => 'cat', // name属性 → GETパラメータ「cat」として送信される
'selected' => $_GET['cat'] ?? '', // 送信された値を保持(再表示時に選択状態を維持)
'taxonomy' => 'product_category', // 使用するタクソノミー(ここでは product_category)
]);
?>
</label>
<!-- 価格帯選択フォーム -->
<label>価格帯:
<select name="price_range">
<option value="">選択してください</option>
<option value="under1000" <?php selected($_GET['price_range'] ?? '', 'under1000'); ?>>
〜1,000円
</option>
<option value="1000to3000" <?php selected($_GET['price_range'] ?? '', '1000to3000'); ?>>
1,000〜3,000円
</option>
<option value="over3000" <?php selected($_GET['price_range'] ?? '', 'over3000'); ?>>
3,000円〜
</option>
</select>
</label>
<!-- フォーム送信ボタン -->
<button type="submit">絞り込む</button>
</form>
📝 コメントのポイント:
wp_dropdown_categories()
は WordPressの便利な関数で、指定したタクソノミー(この場合はproduct_category
)の一覧を<select>
にしてくれます。$_GET['xxx'] ?? ''
で選択値を保持する処理を入れておくと、再読み込み時にも選択状態が保たれて UX が向上します。selected()
は WordPress のフォームヘルパー関数で、対象値が選択されたときにselected
属性を出力します。
🧠 条件に応じて $args
を追加
🧠 GET値をもとにクエリ条件を構築する
// -----------------------------
// カスタムフィールド(価格)による絞り込み条件を格納
// -----------------------------
$meta_query = [];
// 「価格帯」が選択されている場合は、該当する条件を $meta_query に追加
if (!empty($_GET['price_range'])) {
switch ($_GET['price_range']) {
case 'under1000':
// 1,000円以下の投稿
$meta_query[] = [
'key' => 'price', // ACFのフィールド名
'value' => 1000, // 上限値
'compare' => '<=', // 以下
'type' => 'NUMERIC', // 数値として比較
];
break;
case '1000to3000':
// 1,000〜3,000円の範囲
$meta_query[] = [
'key' => 'price',
'value' => [1000, 3000], // 範囲指定
'compare' => 'BETWEEN', // 範囲内
'type' => 'NUMERIC',
];
break;
case 'over3000':
// 3,000円以上の投稿
$meta_query[] = [
'key' => 'price',
'value' => 3000,
'compare' => '>=', // 以上
'type' => 'NUMERIC',
];
break;
}
}
// -----------------------------
// カテゴリー(タクソノミー)による絞り込み条件を格納
// -----------------------------
$tax_query = [];
// 「カテゴリー」が選択されている場合は、$tax_query に条件を追加
if (!empty($_GET['cat'])) {
$tax_query[] = [
'taxonomy' => 'product_category', // カスタムタクソノミー名
'field' => 'term_id', // GETで送られてくる値は term_id
'terms' => intval($_GET['cat']) // 数値に変換して指定
];
}
// -----------------------------
// WP_Query の引数を組み立てる
// -----------------------------
$args = [
'post_type' => 'product', // 投稿タイプ(商品)
'posts_per_page' => 6, // 表示件数
'meta_query' => $meta_query, // 価格帯の絞り込み条件
'tax_query' => $tax_query, // カテゴリーの絞り込み条件
];
📝補足アドバイス:
meta_query
やtax_query
は、条件がなければ自動的にスルーされるので、安心して動的に追加できます。BETWEEN
や>=
のような比較演算子は、type
によって意味が変わるので、数値系なら必ずNUMERIC
を明示しましょう。intval()
はセキュリティ的にも重要で、GET値を確実に整数に変換することで意図しない値の注入を防ぎます。
📌さらに補足: このサンプルでは、product
というカスタム投稿タイプと、product_category
というカスタムタクソノミーを使用しています。 まだ未設定の方は、第5回:カスタム投稿タイプを作ろう や 第13回:ACFで投稿にメタ情報を追加 を参考にしてください。
✅ ページネーション対応($pagedも忘れずに)
// -----------------------------
// 現在のページ番号を取得(ページネーション対応)
// -----------------------------
// get_query_var('paged') は現在のページ番号を取得する関数(1ページ目は0や空になることがある)
// 「 ?: 」は null 合体演算子。値が空なら 1 を代入する(つまり 1ページ目として扱う)
$paged = get_query_var('paged') ?: 1;
// 取得したページ番号を WP_Query の引数に追加
$args['paged'] = $paged;
💡補足ポイント
- ページネーションを使うときに
$paged
を明示しないと、2ページ目以降が「表示されない」現象が起きやすいです。 - 特に
WP_Query
を手動で書いた場合は、必ず'paged' => $paged
を入れるのが基本です!
📝 まとめ
- フロントUI(フォーム)と
WP_Query
を組み合わせることで、柔軟な一覧表示が実現できる $_GET
で受け取った値に応じてmeta_query
やtax_query
を組み立てるonchange
イベントとselected()
の工夫でスムーズなUI体験に- すべての項目にページネーション処理も忘れずに
💬補足: まだ product
投稿タイプや ACF を導入していない方は、
以下の記事で事前準備の方法を紹介していますので、そちらも参考にしてください👇
🔮 次回予告
第17回では、
ユーザー操作に応じて 非同期(Ajax)で一覧を切り替える 方法にステップアップ!
ページリロードなしで、軽快なフィルターUIを実装していきます!