PHPackages                             arraypress/wp-register-list-filters - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. arraypress/wp-register-list-filters

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

arraypress/wp-register-list-filters
===================================

Lightweight library for registering custom list table filters in WordPress admin.

111PHP

Since Nov 23Pushed 5mo agoCompare

[ Source](https://github.com/arraypress/wp-register-list-filters)[ Packagist](https://packagist.org/packages/arraypress/wp-register-list-filters)[ RSS](/packages/arraypress-wp-register-list-filters/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

WordPress Register List Filters
===============================

[](#wordpress-register-list-filters)

A powerful, elegant library for adding custom filters to WordPress admin list tables (posts, pages, custom post types, and users).

Features
--------

[](#features)

- 🎯 **Simple API** - Register filters with a single function call
- 📊 **Multiple Filter Types** - Taxonomy, meta field, and custom query filters
- 🔍 **Auto-Detection** - Automatically fetches taxonomy terms
- 🎨 **Smart UI** - Filters appear inline with WordPress's native interface
- 🔒 **Capability Support** - Restrict filters by user capabilities
- 🚀 **Performance** - Lazy-loads options and uses proper WordPress queries
- 🔗 **AND Logic** - Multiple filters drill down (Engineering + Inactive = both)
- ✨ **Clean Code** - Modern PHP 7.4+, fully typed, well-documented

Installation
------------

[](#installation)

Install via Composer:

```
composer require arraypress/wp-register-list-filters
```

Quick Start
-----------

[](#quick-start)

### Post Filters

[](#post-filters)

```
use function ArrayPress\RegisterListFilters\register_post_list_filters;

// Add filters to the Posts list table
register_post_list_filters( 'post', [
    // Taxonomy filter (auto-fetches terms)
    'category' => [
        'label'      => 'Category',
        'taxonomy'   => 'category',
        'show_count' => true,
        'hide_empty' => false
    ],

    // Meta field filter
    'status' => [
        'label'   => 'Status',
        'options' => [
            'active'   => 'Active',
            'inactive' => 'Inactive',
            'pending'  => 'Pending'
        ]
    ],

    // Boolean meta filter
    '_featured' => [
        'label'   => 'Featured Status',
        'options' => [
            '1' => 'Featured',
            '0' => 'Not Featured'
        ]
    ]
] );
```

### User Filters

[](#user-filters)

```
use function ArrayPress\RegisterListFilters\register_user_list_filters;

// Add filters to the Users list table
register_user_list_filters( [
    // Meta field filter
    'department' => [
        'label'   => 'Department',
        'options' => [
            'sales'       => 'Sales',
            'engineering' => 'Engineering',
            'marketing'   => 'Marketing'
        ]
    ],

    // Custom query callback
    'registered' => [
        'label'   => 'Registered',
        'options' => [
            'today'       => 'Today',
            'last_7_days' => 'Last 7 Days',
            'this_year'   => 'This Year'
        ],
        'query_callback' => function( $query, $value ) {
            $date_query = [];

            switch ( $value ) {
                case 'today':
                    $date_query = [
                        'after'  => date( 'Y-m-d' ) . ' 00:00:00',
                        'before' => date( 'Y-m-d' ) . ' 23:59:59'
                    ];
                    break;
                case 'last_7_days':
                    $date_query = [ 'after' => '7 days ago' ];
                    break;
                case 'this_year':
                    $date_query = [ 'after' => date( 'Y' ) . '-01-01' ];
                    break;
            }

            if ( ! empty( $date_query ) ) {
                $query->set( 'date_query', [ $date_query ] );
            }
        }
    ]
] );
```

### Custom Post Type Filters

[](#custom-post-type-filters)

```
// Register custom post type
register_post_type( 'product', [
    'labels' => [
        'name'          => 'Products',
        'singular_name' => 'Product'
    ],
    'public'      => true,
    'has_archive' => true
] );

// Add filters for the custom post type
register_post_list_filters( 'product', [
    // Taxonomy filter
    'product_brand' => [
        'label'      => 'Brand',
        'taxonomy'   => 'product_brand',
        'show_count' => true
    ],

    // Meta filter
    '_stock_status' => [
        'label'   => 'Stock',
        'options' => [
            'in_stock'     => 'In Stock',
            'out_of_stock' => 'Out of Stock'
        ]
    ],

    // Custom callback for price range
    'price_range' => [
        'label'   => 'Price Range',
        'options' => [
            'under_50'  => 'Under $50',
            '50_to_100' => '$50 - $100',
            'over_100'  => 'Over $100'
        ],
        'query_callback' => function( $query, $value ) {
            $meta_query = [];

            switch ( $value ) {
                case 'under_50':
                    $meta_query = [
                        'key'     => '_price',
                        'value'   => 50,
                        'compare' => '',
                        'type'    => 'NUMERIC'
                    ];
                    break;
            }

            if ( ! empty( $meta_query ) ) {
                $query->set( 'meta_query', [ $meta_query ] );
            }
        }
    ]
] );
```

Filter Configuration
--------------------

[](#filter-configuration)

### Common Options

[](#common-options)

All filter types support these options:

OptionTypeDefaultDescription`label``string`*Required*Label for the dropdown placeholder`capability``string``manage_options`Capability required to see filter`options``array``[]`Manual options (key =&gt; label)### Taxonomy Filters

[](#taxonomy-filters)

For taxonomy-based filters, add these options:

OptionTypeDefaultDescription`taxonomy``string``''`Taxonomy slug to fetch terms from`show_count``bool``false`Show post count next to term name`hide_empty``bool``true`Hide terms with no posts**Example:**

```
'category' => [
    'label'      => 'Category',
    'taxonomy'   => 'category',
    'show_count' => true,
    'hide_empty' => false  // Show all categories, even empty ones
]
```

### Meta Field Filters

[](#meta-field-filters)

For meta field filters, the filter key is used as the meta\_key:

```
// Automatically uses 'department' as meta_key
'department' => [
    'label'   => 'Department',
    'options' => [
        'sales' => 'Sales',
        'engineering' => 'Engineering'
    ]
]
```

For meta keys with underscores, include them in the key:

```
'_featured' => [
    'label'   => 'Featured',
    'options' => [
        '1' => 'Yes',
        '0' => 'No'
    ]
]
```

### Custom Query Callbacks

[](#custom-query-callbacks)

For complex filtering logic, use a custom callback:

```
'custom_filter' => [
    'label'   => 'Custom Filter',
    'options' => [
        'option1' => 'Option 1',
        'option2' => 'Option 2'
    ],
    'query_callback' => function( $query, $value ) {
        // For posts: $query is WP_Query object
        // For users: $query is QueryArgsAdapter object

        // Modify the query based on selected value
        if ( $value === 'option1' ) {
            $query->set( 'meta_query', [
                [
                    'key'     => '_custom_field',
                    'value'   => 'custom_value',
                    'compare' => '='
                ]
            ] );
        }
    }
]
```

Multiple Post Types
-------------------

[](#multiple-post-types)

Apply the same filters to multiple post types:

```
register_post_list_filters( [ 'post', 'page' ], [
    '_visibility' => [
        'label'   => 'Visibility',
        'options' => [
            'public'  => 'Public',
            'private' => 'Private'
        ]
    ]
] );
```

Capability Restrictions
-----------------------

[](#capability-restrictions)

Restrict filters to specific user capabilities:

```
register_post_list_filters( 'post', [
    '_admin_notes' => [
        'label'      => 'Admin Notes',
        'capability' => 'manage_options',  // Only admins can see this
        'options'    => [
            'flagged'  => 'Flagged',
            'reviewed' => 'Reviewed'
        ]
    ]
] );
```

AND Logic (Drill-Down Filtering)
--------------------------------

[](#and-logic-drill-down-filtering)

Multiple filters use AND logic for drill-down filtering:

1. Select "Engineering" from Department → Shows 25 users
2. Add "Inactive" filter → Shows only inactive engineers (fewer results)
3. Add "This Year" registration filter → Shows inactive engineers who registered this year

This is standard WordPress behavior and matches user expectations.

How It Works
------------

[](#how-it-works)

### Posts

[](#posts)

- Uses `restrict_manage_posts` action to render filters
- Uses `parse_query` action to modify WP\_Query
- Builds proper `meta_query` and `tax_query` arrays with AND relations

### Users

[](#users)

- Uses `restrict_manage_users` action to render filters
- Uses `users_list_table_query_args` filter to modify user query
- Prevents duplicate rendering (action fires twice per page)

Technical Details
-----------------

[](#technical-details)

### Timing

[](#timing)

The library automatically handles WordPress hook timing:

- Checks if `init` has fired (taxonomies are registered)
- Loads hooks on `admin_init` (proper admin context)
- No manual hook management needed

### Meta Queries

[](#meta-queries)

For multiple meta filters, the library builds proper meta\_query arrays:

```
// Single filter
[
    'meta_key'   => 'department',
    'meta_value' => 'engineering'
]

// Multiple filters (AND logic)
[
    'meta_query' => [
        'relation' => 'AND',
        [
            'key'   => 'department',
            'value' => 'engineering'
        ],
        [
            'key'   => 'user_status',
            'value' => 'active'
        ]
    ]
]
```

### Taxonomy Queries

[](#taxonomy-queries)

Similar approach for taxonomy filters:

```
[
    'tax_query' => [
        'relation' => 'AND',
        [
            'taxonomy' => 'category',
            'field'    => 'slug',
            'terms'    => 'technology'
        ],
        [
            'taxonomy' => 'post_tag',
            'field'    => 'slug',
            'terms'    => 'featured'
        ]
    ]
]
```

Requirements
------------

[](#requirements)

- PHP 7.4 or higher
- WordPress 5.0 or higher

Contributing
------------

[](#contributing)

Contributions are welcome! Please feel free to submit a Pull Request.

License
-------

[](#license)

GPL-2.0-or-later

Credits
-------

[](#credits)

Developed by [ArrayPress](https://arraypress.com/)

Support
-------

[](#support)

- [Documentation](https://github.com/arraypress/wp-register-list-filters)
- [Issue Tracker](https://github.com/arraypress/wp-register-list-filters/issues)

###  Health Score

19

—

LowBetter than 10% of packages

Maintenance48

Moderate activity, may be stable

Popularity7

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity13

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/cd6eb8aff0903d87eb674d1ba3c5f3653899c0d7661504eb0deb7798ed86b643?d=identicon)[arraypress](/maintainers/arraypress)

---

Top Contributors

[![arraypress](https://avatars.githubusercontent.com/u/22668877?v=4)](https://github.com/arraypress "arraypress (13 commits)")

### Embed Badge

![Health badge](/badges/arraypress-wp-register-list-filters/health.svg)

```
[![Health](https://phpackages.com/badges/arraypress-wp-register-list-filters/health.svg)](https://phpackages.com/packages/arraypress-wp-register-list-filters)
```

###  Alternatives

[treeware/plant

13355.9k6](/packages/treeware-plant)[aschmelyun/size

Simple PHP helper to convert bytes to different sizes

471.2k](/packages/aschmelyun-size)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
