SearchWP Documentation

View the installation guide, browse the Knowledge Base, find out about SearchWP’s many hooks

WPFilters is designed to work with WordPress’s main query on standard archive pages, category pages, and blog home pages. However, when you create a custom page template with your own WP_Query, the posts you want to filter come from your custom query rather than WordPress’s main query (which represents the page itself).

To make WPFilters work with a custom WP_Query, you need to mark the query with a special flag and use specific HTML markup. This tells WPFilters to apply filtering logic to your custom query and allows the frontend JavaScript to update the correct parts of the page when users interact with filters.

Required Setup

Query Flag

You must add ‘wpfilters’ => true to your WP_Query arguments. This marks the query so WPFilters applies its filtering logic, reads filter parameters from the URL, calculates which post IDs match the selected filters, and updates the query accordingly.

Without this flag, WPFilters treats your query as a regular unfiltered query and ignores it completely.

Note: Do not use ‘suppress_filters’ => true in your query arguments. WPFilters treats suppressed queries the same way WordPress treats get_posts() calls and skips them entirely. 

Your query must allow filters to run for WPFilters to work properly.

Required HTML Markup

WPFilters relies on specific CSS classes and HTML structure so the frontend JavaScript can locate and update the correct page elements during AJAX filtering:

Results Wrapper: Your post loop output must be wrapped in an element with the class wpfilters-results. After a filter AJAX request, WPFilters replaces the content inside this wrapper with the filtered results.

Pagination Wrapper: Your pagination links should be wrapped in an element with the class wpfilters-pagination. This allows the JavaScript to find and update pagination after filtering.

Without these wrapper classes, the AJAX updates may fail or target the wrong page elements, causing the filter interface to malfunction.

Example Template

The following example shows a complete custom page template that works with WPFilters. This template is designed for classic WordPress themes that use get_header() and get_footer(), such as Twenty Twenty or custom child themes.

<?php
/**
* Template Name: WP Filters — custom query
*
* @package YourTheme
*/
get_header();
?>
<main id="primary" class="site-main">
<div class="section-inner">
<header class="page-header">
<h1 class="entry-title">
<?php esc_html_e( 'Custom query with WPFilters', 'your-textdomain' ); ?>
</h1>
</header>
<div class="wpfilters-wrapper">
<aside
class="wpfilters-sidebar widget-area"
role="complementary"
aria-label="<?php esc_attr_e( 'Filters', 'your-textdomain' ); ?>"
>
<?php
if ( class_exists( '\WPFilters\Renderer' ) ) {
echo \WPFilters\Renderer::render( 1 ); // Search.
echo \WPFilters\Renderer::render( 2 ); // Category.
echo \WPFilters\Renderer::render( 3 ); // Post type.
}
?>
</aside>
<div class="wpfilters-content content-area">
<?php
// Page templates use `page`; archives use `paged`.
$paged = max(
1,
(int) get_query_var( 'paged' ),
(int) get_query_var( 'page' )
);
$args = array(
'post_type' => array( 'post', 'page' ),
'post_status' => 'publish',
'posts_per_page' => 10,
'paged' => $paged,
'orderby' => 'title',
'order' => 'ASC',
'wpfilters' => true,
);
$query = new WP_Query( $args );
?>
<?php if ( $query->have_posts() ) : ?>
<div class="wpfilters-results">
<?php
while ( $query->have_posts() ) :
$query->the_post();
?>
<article
id="post-<?php the_ID(); ?>"
<?php post_class( 'entry' ); ?>
>
<h2 class="entry-title">
<a href="<?php the_permalink(); ?>">
<?php the_title(); ?>
</a>
</h2>
<div class="entry-summary">
<?php the_excerpt(); ?>
</div>
</article>
<?php endwhile; ?>
</div>
<nav
class="wpfilters-pagination navigation pagination"
aria-label="<?php esc_attr_e( 'Posts pagination', 'your-textdomain' ); ?>"
>
<?php
echo paginate_links(
array(
'total' => $query->max_num_pages,
'current' => $paged,
'mid_size' => 2,
'prev_text' => __( 'Previous', 'your-textdomain' ),
'next_text' => __( 'Next', 'your-textdomain' ),
)
);
?>
</nav>
<?php else : ?>
<p class="wpfilters-results">
<?php esc_html_e( 'No posts found.', 'your-textdomain' ); ?>
</p>
<?php endif; ?>
<?php wp_reset_postdata(); ?>
</div>
</div>
</div>
</main>
<?php
get_footer();
?>

How the Template Works

The wpfilters Query Flag

The ‘wpfilters’ => true argument in the WP_Query marks this query for WPFilters processing. When this flag is present, WPFilters applies its filtering logic by reading filter parameters from the URL, calculating which post IDs match the selected filters, and (during AJAX requests) setting post__in to display only the matching posts.

Results Wrapper

The <div class=”wpfilters-results”> element wraps the entire post loop output. This wrapper is critical because the frontend JavaScript looks for this class to find where to inject filtered results. After a filter AJAX request completes, WPFilters replaces the content inside this wrapper with the new filtered posts.

For consistency, even the “no posts found” message is wrapped in an element with the wpfilters-results class. This ensures a stable target element exists whether posts are found or not.

Pagination Wrapper

The <nav class=”wpfilters-pagination”> element wraps the paginate_links() output. This wrapper allows the JavaScript to locate and update pagination links after filtering. Without this wrapper, pagination might not update correctly when filters change.

Pagination Variable Handling

Page templates use the page query variable for pagination, while archives use paged. The template code handles both by taking the maximum value of either variable, ensuring pagination works correctly regardless of which variable WordPress sets.

Important Considerations

Align Query with Filter Sources

Filter options are automatically generated based on the post types included in your WP_Query. WPFilters only displays filter options that are relevant to the post types you’re querying. If your WP_Query doesn’t include post types that have the taxonomy or custom field data your filters are built from, those filter options will not appear.

For example, if your filter element is configured to show categories but your WP_Query only includes the page post type, the category filter will appear empty because pages typically don’t have category assignments. Similarly, if you have a custom taxonomy filter for WooCommerce products but your query only includes regular posts, no filter options will display because posts don’t use product taxonomies.

Preserve URL Parameters in Pagination

WPFilters adds filter selections to the URL as query parameters. When users navigate between pages, these parameters must be preserved so filters remain active. You can extend the paginate_links() function with the ‘add_args’ parameter to keep filter parameters in pagination links.

Only pass safe, known parameter keys to avoid security issues. Do not blindly copy all values from $_GET without validation.

Block and Full Site Editing Themes

If you’re using a block theme or Full Site Editing (FSE) theme that doesn’t have traditional header.php and footer.php files, this template example will not work as written. For block themes, you’ll need to either create a child theme with classic template support or use the block theme’s equivalent HTML template parts and block patterns.

Installation and Setup

File Location

Save the template file in your active theme directory. For a parent theme, place it at: wp-content/themes/your-theme/wp-filters-query.php

For better maintainability, use a child theme: wp-content/themes/your-child-theme/wp-filters-query.php

Assign Template to a Page

  1. Go to Pages → Add New in your WordPress admin
  2. In the sidebar, find the Template option
  3. Select “WP Filters — custom query”
  4. Publish or update the page

Visit the page on the frontend and test your filters and pagination.

Summary

Using WPFilters with a custom WP_Query gives you full control over how content is displayed and filtered. By properly marking your query and structuring your template, you can build powerful, dynamic filtering experiences beyond standard WordPress archives.

Create a Better WordPress Search Experience Today

Never lose visitors to unhelpful search results again. SearchWP makes creating your own smart WordPress search fast and easy.

Get SearchWP Now
Multiple Search Engines Icon