# Filter an Admin List by a Custom Field

> Adds a dropdown above a post type's admin list with every value used in a custom field (such as city or brand), so you can show only matching items.

- Type: PHP
- Runs: Admin only
- Category: [Custom Post Types & Fields](https://wpide.com/library/category/post-types/)
- Tags: admin, filters, custom-fields
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/admin-filter-by-meta/

## Code

```php
// Post type, meta key and dropdown label.
$wpide_meta_filter = array(
    'post_type' => 'post',
    'meta_key'  => 'location',
    'label'     => 'All locations',
);

add_action( 'restrict_manage_posts', function ( $post_type ) use ( $wpide_meta_filter ) {
    global $wpdb;

    if ( $wpide_meta_filter['post_type'] !== $post_type ) {
        return;
    }

    $key    = 'wpide_meta_filter_' . md5( $wpide_meta_filter['post_type'] . $wpide_meta_filter['meta_key'] );
    $values = get_transient( $key );

    if ( false === $values ) {
        $values = $wpdb->get_col( $wpdb->prepare(
            "SELECT DISTINCT pm.meta_value FROM {$wpdb->postmeta} pm INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
             WHERE pm.meta_key = %s AND p.post_type = %s AND pm.meta_value <> '' ORDER BY pm.meta_value LIMIT 200",
            $wpide_meta_filter['meta_key'],
            $wpide_meta_filter['post_type']
        ) );
        set_transient( $key, $values, HOUR_IN_SECONDS );
    }

    if ( ! $values ) {
        return;
    }

    $current = isset( $_GET['wpide_meta'] ) ? sanitize_text_field( wp_unslash( $_GET['wpide_meta'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification

    echo '<label class="screen-reader-text" for="wpide-meta-filter">' . esc_html( $wpide_meta_filter['label'] ) . '</label><select name="wpide_meta" id="wpide-meta-filter"><option value="">' . esc_html( $wpide_meta_filter['label'] ) . '</option>';

    foreach ( $values as $value ) {
        printf( '<option value="%1$s"%2$s>%3$s</option>', esc_attr( $value ), selected( $current, $value, false ), esc_html( wp_trim_words( $value, 8 ) ) );
    }

    echo '</select>';
} );

add_action( 'pre_get_posts', function ( $query ) use ( $wpide_meta_filter ) {
    if ( ! is_admin() || ! $query->is_main_query() || $wpide_meta_filter['post_type'] !== $query->get( 'post_type' ) || empty( $_GET['wpide_meta'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
        return;
    }

    $meta_query   = (array) $query->get( 'meta_query' );
    $meta_query[] = array( 'key' => $wpide_meta_filter['meta_key'], 'value' => sanitize_text_field( wp_unslash( $_GET['wpide_meta'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification
    $query->set( 'meta_query', $meta_query );
} );

add_action( 'save_post_' . $wpide_meta_filter['post_type'], function () use ( $wpide_meta_filter ) {
    delete_transient( 'wpide_meta_filter_' . md5( $wpide_meta_filter['post_type'] . $wpide_meta_filter['meta_key'] ) );
} );
```

## Notes

Set the post type, meta key and label. The list of values is cached for an hour and refreshed when an item is saved.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Filter an Admin List by a Custom Field" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
