How to Add Multi-Select Dropdown Filters to a WordPress Table

Updated July 2026 • 7 min read • By Fahad Murtaza

TableCrafter live search, sorting, filtering, and pagination out of the box
TableCrafter live search, sorting, filtering, and pagination out of the box

A standard dropdown filter forces users to choose one value at a time. If your table has a Status column and a user wants to see both Pending and Approved rows simultaneously, a single-select filter makes them run the same lookup twice. Multi-select dropdown filters solve this in one interaction. This guide explains how to enable them in TableCrafter, how the query logic works, and what to watch out for with lookup field options. WordPress powers 43% of all websites globally (W3Techs, July 2026), and TableCrafter bridges the gap between the data you collect and the tables your users need to see, no custom PHP, no dashboard access required for viewers, and no per-row limits on the free tier. The free version on WordPress.org supports CSV, JSON, Google Sheets, and Excel. Pro adds Gravity Forms, Airtable, Notion, WooCommerce, REST APIs, inline cell editing, export to CSV/PDF, role-based column visibility,. WordPress multisite installations account for approximately 3.4% of all WordPress deployments (WordPress.org, 2025).

What Multi-Select Filters Do?

When multi-select is enabled on a column, the dropdown lets users check multiple values from the list. The active selections appear as removable tags inside the filter input. The table re-queries each time the selection changes, applying OR logic across the selected values within a column: a row is included if it matches any of the chosen options.

Example: with Status values of Pending, Approved, and Rejected, selecting Pending and Approved shows every row where Status is Pending OR Status is Approved. Rejected rows are excluded.

When filters are active on more than one column simultaneously, the logic between columns is AND: a row must match the multi-select condition on column A AND the filter condition on column B to appear in the result. This means multi-select within a column gives users flexible OR-based exploration, while combining multiple filtered columns lets them narrow the result set precisely.

For Gravity Forms multiselect fields, where multiple chosen values are stored as a comma-separated string in the entry, TableCrafter's TC_Multiselect_Filter_Service splits each cell into its constituent values before comparing, so a cell containing Pending, Approved matches a filter for either value individually using case-insensitive comparison.

After completing this step, verify the result by viewing the page as a logged-out visitor in an incognito window. This confirms the table behaves correctly for public visitors rather than reflecting admin-level permissions that may hide configuration issues during initial setup. Check both the rendered output and the browser console for any JavaScript errors.

Step 1: How Do I Enable the Filter on the Column?

Open the table builder at TableCrafter → Tables → Edit. Click the funnel icon on the column you want to make multi-selectable. In the Filter Settings panel:

  1. Set Filter Type to Select
  2. Enable the Allow Multiple Selections toggle that appears below the type selector
  3. Click Save Column

The multi-select toggle only appears when the filter type is Select, it is hidden for Text and Date types, which do not support multiple simultaneous values.

The column mapping you define here is stored as a JSON configuration in the WordPress database. You can export this configuration using the TableCrafter export tool and import it to another table or another site. This is useful when replicating a table layout across multiple pages or when migrating a table to a staging environment for testing before going live.

Multi-select is a Pro feature. On the free plan, the Allow Multiple Selections toggle is visible but disabled. Upgrading unlocks it without needing to reconfigure your columns.

Step 2: How Do I Place the Shortcode?

Multi-select filters require the same shortcode parameter as standard filters. Add a Shortcode block or Custom HTML block on the page where you want the table and paste:

[tablecrafter id="1" filter="true"]

No extra shortcode parameter is needed to activate multi-select specifically — it activates based on the column configuration you saved in the builder. If you have several columns and only some are configured as multi-select, those columns render as multi-select checkboxes in the filter bar while the others render as standard single-select dropdowns. The filter bar renders above the table automatically when filter="true" is present, regardless of whether any filter type is single or multi-select.

After publishing the page, test the multi-select behavior by selecting two or more options in one of the multi-select filter dropdowns and verifying the table returns only rows that match at least one of the selected values (OR logic). If the table returns no results when multiple options are selected, check the Filter tab in the table builder — multi-select filters use OR logic by default and AND logic must be explicitly configured per column. In most use cases, OR logic is the intended behavior: show me all entries where Status is either "Pending" or "In Progress."

What Is the UI Behavior Explained?

On the frontend, a multi-select filter column renders as a custom dropdown widget (not a native HTML <select multiple> element). When the user clicks the filter input, a panel opens listing all available values as checkboxable items. Checked items accumulate as pill-shaped tags inside the input field. The filter icon on the input turns blue when one or more values are selected, giving a clear visual signal that the column is actively filtered.

Removing a single selection is done by clicking the × on its pill tag. Removing all selections for the column at once is done by clicking the small clear icon at the right of the input. The global Reset All Filters button clears every multi-select and single-select filter simultaneously.

TableCrafter re-fetches this data on each page load by default. If your data source updates infrequently and your site has significant traffic, enable the built-in caching option in the table's Performance tab. This stores the fetched data for a configurable number of minutes and serves it from WordPress transients, reducing API calls to the source and improving page load time for visitors.

How the Filter Query Is Constructed?

Under the hood, when a user selects multiple values TableCrafter passes an array of selected values to the server in the AJAX request body:

POST /wp-admin/admin-ajax.php
Action: gt_get_entries

{
  "table_id": 1,
  "filters": {
    "status": ["Pending", "Approved"]
  }
}

The server-side filter handler detects that the filter value is an array and builds a SQL IN (...) clause or, for Gravity Forms sources, a field_filters block with operator: "in". This means the filtering happens at the database layer, only matching rows are returned, not all rows with client-side hiding.

This approach scales correctly for large datasets. A table with 50,000 rows filters just as fast whether you select one status value or five, because the database does the work and the AJAX response only carries the matching rows.

The configuration you set here applies to every visitor who loads a page containing this table, regardless of whether they are logged in. Role-specific overrides for columns and rows are a separate layer and do not replace these global display settings. Apply global settings first, then add role restrictions as needed for tables that serve multiple user types.

What Is Lookup Field Options: Common Gotchas?

Lookup fields are columns whose displayed values come from a related record rather than the raw entry field, for example, a Gravity Forms entry that stores a user ID but displays that user's full name. Multi-select filters on lookup fields have a few specific behaviors to know:

The Dropdown Populates From Display Values

TableCrafter's multi-select dropdown is populated from the display values it has already rendered, not from the underlying IDs. This means the filter list shows "Jane Smith" rather than user ID 47. When the user selects "Jane Smith," TableCrafter maps the display name back to the raw stored value before querying the data source. If the lookup mapping is misconfigured, the dropdown may show correct labels but return zero results because the label-to-value map is broken.

The TC_Multiselect_Filter_Service handles this for Gravity Forms multiselect field types. It splits the stored comma-separated string into individual values and performs a case-insensitive comparison, so a cell storing Pending, Approved matches a filter selection of either Pending or Approved regardless of capitalization stored in the entry.

For lookup fields that resolve to display names, the mapping between what is shown in the dropdown and what is stored in the entry data must be correct for filtering to work. If you see zero results after selecting a value that clearly exists in the table, open the column configuration and confirm the Value Field setting points to the raw field that the entry data contains, not the resolved display label field. A mismatch here is the most common cause of filters that appear to work but return empty tables.

If your multi-select dropdown shows correct options but filtering returns no rows, check the lookup field configuration. The Value Field setting in the lookup configuration must point to the same raw field that the data source stores, not the label field.

Options May Not Include All Possible Values

By default, the dropdown option list is built from the values present in the current result set. If pagination is active and only 25 rows are loaded, the dropdown may only show values from those 25 rows, missing values that exist further in the dataset. To fix this, enable the Load All Options setting in the column's filter settings panel. This triggers a separate lightweight query that fetches all distinct values for that column across every row in the form, independent of the current page view.

The distinct values query uses the same approach as TC_Multiselect_Filter_Service::distinct_values() internally: it iterates entries, splits comma-separated values for GF multiselect field types, and returns a deduplicated alphabetically sorted list. For standard dropdown fields it runs a simpler distinct-values query against the field column.

Enabling Load All Options adds one extra request at page load but eliminates the confusion of a filter dropdown that appears to have only partial options. For tables where the distinct value set is small and static, the overhead is minimal. For tables with thousands of rows, the option query runs separately from the main data query and does not slow down the initial table render. Pair it with the server-side option cache in TableCrafter → Settings → Performance to avoid re-running the query on every page load.

Option Ordering

By default, options appear in the order they are encountered in the data, which may vary between page loads if the underlying result set changes. Enable Sort Options Alphabetically in the filter settings for a predictable A-Z option list that stays consistent regardless of data order.

TC_Multiselect_Filter_Service::distinct_values() uses a case-insensitive alphabetical sort internally, so for Gravity Forms multiselect fields the alphabetical ordering is already applied when Load All Options is enabled. For standard dropdown columns the sorting behavior follows the same Sort Options Alphabetically setting in the column's filter panel.

For numeric values such as priority levels 1 through 5, alphabetical sorting produces the lexicographic order 1, 10, 2, 3, 4, 5 if two-digit values exist. In those cases, leave the alphabetical setting off and consider zero-padding stored values (01, 02, 10) so alphabetical and numeric orderings align. Alternatively, use the Static Options setting in the column's filter panel to define the option list manually in the correct display order, which overrides the dynamic distinct-values query entirely.

For text-based status fields like Pending, In Progress, Complete, and Archived, alphabetical sorting usually produces a sensible display order without any additional configuration.

How Does Multi-Select With Lookup Fields That Map to Users Work?

User lookup fields — where the stored value is a WordPress user ID integer and the displayed value is a user's display name — work with multi-select, but the option loading behavior differs from regular dropdown fields. Standard dropdown filters load their options from the distinct values present in the entry data. User lookup fields cannot do this because the entry data contains user IDs (integers), not display names, and the multi-select filter needs to show display names as checkboxes.

To support this, enable the Load All Options setting in the column's Filter tab. This setting causes TableCrafter to run a separate query against wp_users to fetch all WordPress users, map them to their display names, and use those as the filter option list. The multi-select checkboxes then show display names (e.g., "Jane Smith", "Marcus Webb") while the underlying filter still queries by user ID. If your site has more than 500 users, enable the Load All Options search field so visitors can type to narrow the options rather than scrolling a long list.

How Does Performance Considerations Work?

Multi-select filters with Load All Options enabled fire an extra database query on page load to populate the dropdown. For tables with hundreds of thousands of rows, this distinct-values query can be slow. TableCrafter caches the option list in the browser's sessionStorage for the duration of the page session, so the query only fires once per page load, not on each selection change. Navigating away and returning to the page resets the session cache and fires the query again on next load.

If the option list rarely changes, for example a static status field that has five possible values, you can set a server-side cache duration in TableCrafter → Settings → Performance to cache the distinct-values query result for a configured number of minutes. This stores the option list in WordPress transients and serves it from cache on subsequent page loads within the cache window, avoiding the database query entirely.

For Gravity Forms multiselect fields where TC_Multiselect_Filter_Service populates the options, the same server-side cache applies. The service's distinct_values() method runs its iteration once, stores the sorted deduplicated result in the transient, and subsequent visitors within the cache window receive the cached list rather than triggering a full entry scan.

This step completes the connection between your data source and the TableCrafter table engine. Once saved, the plugin caches the connection credentials in the WordPress options table and uses them on every subsequent page load. If you update the source configuration later — for example, rotating an API key or changing a sheet URL — return to this step, enter the new value, and save again. The table updates immediately on next load without any shortcode changes.

What Are the Next Steps?

With multi-select filters in place, users can slice your data along multiple values in any filterable column. The OR-within-column logic combined with AND-across-columns behavior gives users expressive filtering without requiring custom search code: selecting Pending or Approved for Status while also filtering by a specific Category returns entries that match both conditions simultaneously.

For date-based columns where users need to filter by a time window rather than a specific value, the next guide covers date range filters, a from/to date picker that maps cleanly onto timestamp data.

If you are pairing multi-select filters with a table that uses auto-refresh, be aware that each refresh re-fetches the full result set from the server using the current active filter state. Multi-select selections persist through refresh cycles, so the table re-applies the same filter array to the new data on each poll and the displayed rows stay consistent with the active selection while new matching entries appear automatically.

For tables with a large number of concurrent users all using multi-select filters, consider enabling the server-side cache for the distinct-values query to reduce the option-loading overhead across page loads. Pair that with the client-side sessionStorage cache already in place to minimize redundant queries from individual users navigating around your site.

Frequently Asked Questions

What do multi-select filters do?

When multi-select is enabled on a column, the dropdown lets users check multiple values from the list. The active selections appear as removable tags inside the filter input. The table re-queries each time the selection changes, applying OR logic across the selected values, a row is included if it matches any of the chosen options.

What Is TableCrafter?

TableCrafter is a WordPress plugin that turns data from Gravity Forms, Google Sheets, Airtable, Notion, REST APIs, CSV files, and WooCommerce into interactive, sortable, filterable frontend tables. Embed any table on any WordPress page with the [tablecrafter] shortcode or the native Gutenberg block. No PHP or custom development required. The free version supports CSV, JSON, Google Sheets, and Excel. Pro adds Gravity Forms, Airtable, Notion, WooCommerce, REST APIs, inline cell editing, export to CSV and PDF, role-based column visibility, and auto-refresh.

Does this require PHP or developer skills?

No. TableCrafter is configured entirely through the WordPress admin interface. You choose your data source, map fields to columns, and set display preferences using point-and-click controls. Embedding uses the [tablecrafter] shortcode or the native Gutenberg block.

Is the free version sufficient or do I need Pro?

The free plugin on WordPress.org supports CSV, JSON, Google Sheets, and Excel sources with unlimited tables, rows, and columns. Pro adds Gravity Forms, Airtable, Notion, WooCommerce, REST API sources, inline cell editing, bulk row actions, export to CSV and PDF, role-based column visibility, and auto-refresh every N seconds.

Ready to try it?

TableCrafter is free on WordPress.org. Pro unlocks inline editing, role-based permissions, and advanced data sources.