How to Query Posts by Custom Field in WordPress (meta_query)

WP_Query supports filtering posts by custom field values via the meta_query parameter. It covers simple equality checks and more complex comparisons — ranges, existence checks, multiple conditions combined with AND/OR.

Problem: How do you retrieve WordPress posts filtered by a custom field (post meta) value?

Solution: Pass a meta_query argument to WP_Query — it supports single-field lookups, multi-field combinations with AND/OR, and numeric comparisons.

Simple single-field query:

$query = new WP_Query( [
    'post_type'  => 'product',
    'meta_query' => [
        [
            'key'     => '_featured',
            'value'   => '1',
            'compare' => '=',
        ],
    ],
] );

Multi-condition query (AND / OR):

$query = new WP_Query( [
    'post_type'  => 'event',
    'meta_query' => [
        'relation' => 'AND',
        [
            'key'     => 'event_city',
            'value'   => 'Kyiv',
            'compare' => '=',
        ],
        [
            'key'     => 'event_date',
            'value'   => date( 'Y-m-d' ),
            'compare' => '>=',
            'type'    => 'DATE',
        ],
    ],
] );

Check for key existence (any value set):

$query = new WP_Query( [
    'post_type'  => 'post',
    'meta_query' => [
        [
            'key'     => '_thumbnail_id',
            'compare' => 'EXISTS',
        ],
    ],
] );

Available compare operators: =, !=, >, >=, <, <=, LIKE, NOT LIKE, IN, NOT IN, BETWEEN, NOT BETWEEN, EXISTS, NOT EXISTS.

NOTE: Meta queries hit wp_postmeta which has no index on meta_value by default. On large datasets, complex meta queries can be slow. Consider adding a composite index on (meta_key, meta_value) or storing frequently-queried flags as post data (taxonomy terms or custom columns) instead.