「3000円以下の商品だけ」「在庫があるものだけ」——カスタムフィールドの値で投稿を絞りこむのがmeta_queryです。基本の形はtax_queryと同じ二重構造です。
<?php
$query = new WP_Query([
'post_type' => 'shohin',
'meta_query' => [
[
'key' => 'price', // フィールド名
'value' => 3000, // 比べる値
'compare' => '<=', // 比べ方
'type' => 'NUMERIC', // 値の型(数値なら必須)
],
],
]);
?>最重要ポイントはtype。これを忘れると数値の大小がおかしくなります(理由は後述)。
4つのキーの意味
| キー | 役割 | よく使う値 |
|---|---|---|
key | カスタムフィールドの名前 | 'price' 'event_date' |
value | 比べる値 | 数値・文字列・配列 |
compare | 比べ方 | '='(既定)'!=' '>' '>=' '<' '<=' 'LIKE' 'IN' 'NOT IN' 'BETWEEN' 'EXISTS' 'NOT EXISTS' |
type | 値の型 | 'CHAR'(既定)'NUMERIC' 'DATE' 'DATETIME' 'DECIMAL' |
なぜtypeが必要なのか
WordPressはカスタムフィールドの値を、種類を区別せず文字列として保存しています。そのためtypeを指定しないと、比較も文字列のルールで行われます。
- 文字列として比べると——
'100'は'99'より小さい(先頭の1と9を比べるため) 'type' => 'NUMERIC'を付けると——数値として比べるので100 > 99
価格・在庫数・点数など数値を扱うときは、必ず'type' => 'NUMERIC'。小数を含むなら'DECIMAL'を使います。
compareの実例
// 在庫が1以上(在庫あり)
['key' => 'stock', 'value' => 0, 'compare' => '>', 'type' => 'NUMERIC'],
// 1000円〜3000円
['key' => 'price', 'value' => [1000, 3000], 'compare' => 'BETWEEN', 'type' => 'NUMERIC'],
// サイズがS・Mのどちらか
['key' => 'size', 'value' => ['S', 'M'], 'compare' => 'IN'],
// 部分一致(説明文に「限定」を含む)
['key' => 'note', 'value' => '限定', 'compare' => 'LIKE'],
// そのフィールドに何か入っている投稿だけ
['key' => 'price', 'compare' => 'EXISTS'],
// そのフィールドが空(または未設定)の投稿だけ
['key' => 'price', 'compare' => 'NOT EXISTS'],BETWEENとINはvalueを配列で渡すのが決まりです。
複数の条件を組み合わせる
relationでつなぎ方を決めます(省略時はAND)。
'meta_query' => [
'relation' => 'AND',
['key' => 'price', 'value' => 3000, 'compare' => '<=', 'type' => 'NUMERIC'],
['key' => 'stock', 'value' => 0, 'compare' => '>', 'type' => 'NUMERIC'],
],入れ子にすれば「(AかB)かつC」も書けます。
'meta_query' => [
'relation' => 'AND',
[
'relation' => 'OR',
['key' => 'is_new', 'value' => '1'],
['key' => 'is_sale', 'value' => '1'],
],
['key' => 'stock', 'value' => 0, 'compare' => '>', 'type' => 'NUMERIC'],
],カスタムフィールドの値で並べ替える
絞りこみとは別に、並べ替えでもカスタムフィールドが使えます。meta_keyとorderbyの組み合わせです。
// 価格の安い順
$query = new WP_Query([
'post_type' => 'shohin',
'meta_key' => 'price',
'orderby' => 'meta_value_num', // 数値として並べる
'order' => 'ASC',
]);'orderby' => 'meta_value_num'——数値として並べる(価格・点数・在庫)'orderby' => 'meta_value'——文字列として並べる(名前・カナ・Ymd形式の日付)
2つの基準で並べ替える(名前付きの条件)
meta_queryの条件に名前を付けると、orderbyからその条件を指定できます。「おすすめ順→価格の安い順」のような多段の並べ替えです。
$query = new WP_Query([
'post_type' => 'shohin',
'meta_query' => [
'featured' => ['key' => 'is_featured', 'compare' => 'EXISTS'],
'price' => ['key' => 'price', 'compare' => 'EXISTS', 'type' => 'NUMERIC'],
],
'orderby' => [
'featured' => 'DESC',
'price' => 'ASC',
],
]);配列のキー(featured price)が条件の名札になり、orderbyでその順番を指定できます。
日付フィールドで絞る
ACF(SCF)の日付フィールドは、既定で20260725のようなYmdの文字列で保存されています。この形式なら文字列のままでも大小比較が正しく効くので、そのまま使えます。
// 今日以降のイベントだけ、開催日の近い順に
$query = new WP_Query([
'post_type' => 'event',
'meta_key' => 'event_date',
'orderby' => 'meta_value',
'order' => 'ASC',
'meta_query' => [
[
'key' => 'event_date',
'value' => date('Ymd'),
'compare' => '>=',
],
],
]);保存形式が2026-07-25のようにハイフン入りの場合は、'type' => 'DATE'を付けて比較します。
実例:絞りこみフォームと組み合わせる
URLのパラメータ(?max_price=3000)を受け取って条件を組み立てるパターンです。
<?php
$args = ['post_type' => 'shohin', 'posts_per_page' => 12];
if (!empty($_GET['max_price'])) {
$args['meta_query'][] = [
'key' => 'price',
'value' => (int) $_GET['max_price'], // 必ず数値に変換
'compare' => '<=',
'type' => 'NUMERIC',
];
}
$query = new WP_Query($args);
?>重くなってきたら設計を見直す
投稿メタは「1行に1つの値」という形で保存されているため、条件が増えるほどデータベースの結合が増えて遅くなります。
- 絞りこみの軸が決まっている(季節・ブランド・カテゴリ)→ カスタムタクソノミーにして
tax_queryのほうが速い - 絞りこみの軸が数値の範囲(価格・面積)→
meta_queryが向いている
「一覧で絞りこみに使う項目はタクソノミー、詳細ページで表示するだけの項目はカスタムフィールド」——この分け方が、あとから効いてくる設計判断です。
べんりワザtax_queryでカテゴリ・タクソノミーで絞りこむタクソノミーで絞りこむtax_queryの書き方はこちらまとめ
meta_queryはkey/value/compare/typeの4点セット。配列の中に条件の配列を入れる- 数値比較には
'type' => 'NUMERIC'が必須(既定は文字列比較で大小が狂う) - 並べ替えは
meta_key+orderby: meta_value_num。値の無い投稿は消えるので注意 - 絞りこみの軸が決まっているなら、タクソノミー化して
tax_queryのほうが速い
条件の書き方が身につくと、「データはあるのに一覧に出せない」という詰まりがなくなります。