WAIT: Performance Issue: Bricks Filter Indexer triggers thousands of SQL queries during WooCommerce Product Import

Browser: Chrome 110
OS: macOS / Windows / Linux / etc.

[Please describe this bug in as much detail as possible so we can replicate & debug this bug]

Hello Bricks Team,

I’ve identified a significant performance bottleneck when importing WooCommerce products while using the native Bricks Filter system.

The Problem: During a standard WooCommerce product import (using WP All Import or native WC importer), the time to process a single product increases from ~1 second to 30+ seconds if Bricks Filters are active.

Technical Details: I ran an SQL profiler during the import of a single product and found that Bricks triggers hundreds of DELETE and SELECT queries on the wp_bricks_filters_index and wp_bricks_filters_element tables for every single meta field update.

For a product with multiple attributes, this results in:

  • Over 800+ SELECT queries to wp_bricks_filters_element.

  • Hundreds of DELETE queries to wp_bricks_filters_index.

  • Total SQL calls per product exceeding 50,000–90,000.

It seems the indexer hooks into updated_post_meta or similar hooks without any “debounce” or “throttling” during bulk processes.

SQL Log Example (per single product):

SQL

-- Repeated 100+ times per product update:
DELETE FROM `wp_bricks_filters_index` WHERE `filter_id` = 'xxxxx' AND `object_id` = 22793;
SELECT wp_bricks_filters_element.* FROM wp_bricks_filters_element ... WHERE indexable = '1';

Requested Improvement: Could you please add a check to disable auto-indexing during bulk imports, or provide a hook to programmatically pause the indexer? Currently, the only way to perform an import is to manually disable the indexer or use a SQL-level block on the tables.

Thank you!

Hi @Faradei ,

Thanks for the detailed report :+1:

This is not a bug. The Query Filters indexer listens to several WordPress hooks so that when posts (including WooCommerce products) are added/updated programmatically, the index stays in sync automatically.

For bulk imports, we recommend this workflow:

  1. Temporarily disable Query Filters.

  2. Run the import.

  3. Re-enable Query Filters.

  4. Manually click Regenerate Index once after the import completes.

This avoids unnecessary overhead during the import and rebuilds the index in one optimized run.

Regards,
Jenn

Hi Jenn,

Thank you for the quick response.

I understand the logic behind the indexer, but the recommended workflow (disabling Query Filters during import) creates a poor experience for live websites.

When “Query Filters” are disabled during a long import (which can take hours for large catalogs), customers browsing the site see PHP errors or broken layouts where the filters should be.

Could the team consider adding a “Disable Indexing Only” toggle in the Bricks settings?

Ideally, we need a way to:

1. Keep the filters visible and working for customers on the frontend (using the existing index).

2. Stop the indexer from listening to hooks and updating the DB only during the import process.

3. Provide a simple constant or filter, like define(‘BRICKS_DISABLE_FILTER_INDEXING’, true);, that we can trigger programmatically during migrations.

Manually toggling the entire module off and on is not a viable solution for production sites with constant updates. Is it possible to implement a more “developer-friendly” way to pause the background indexing without breaking the frontend?

Hi @Faradei ,

Understand your request.

May I know how often you will perform posts/data import to your live site?

Your live site will not be placed in Maintenance mode during the data import process (as it will take a few hours)

If we provide such an option, this will lead to a scenario where the filter counts don’t match the filter results during the import process.

Or you are referring to having a"Disable autoindex" setting. So you always manually generate the index, because there is no way to know when you are importing data?

Hi Jenn,

We import/update products daily via WP All Import cron, so the site is always live — maintenance mode is not an option.

But honestly, I think a “Disable autoindex” toggle isn’t even necessary. The real issue is simpler: there’s no debounce on handle_post_meta_update.

I looked at the source code (query-filters.php, line 73–1199). Currently, every single updated_post_meta hook calls index_post() synchronously. When WooCommerce saves a product, it updates 20–50 meta fields — so index_post() runs 20–50 times for the same post, with the same result each time.

A simple fix would be to collect post IDs and index them once on shutdown instead of on every meta update:

private $posts_to_index = [];

public function handle_post_meta_update( $meta_id, $object_id, $meta_key, $meta_value ) {
    if ( wp_is_post_revision( $object_id ) || self::$is_saving_post ) {
        return;
    }
    // Debounce: just queue the post ID
    if ( ! in_array( $object_id, $this->posts_to_index ) ) {
        $this->posts_to_index[] = $object_id;
    }
    if ( count( $this->posts_to_index ) === 1 ) {
        add_action( 'shutdown', [ $this, 'flush_pending_index' ] );
    }
}

public function flush_pending_index() {
    foreach ( $this->posts_to_index as $post_id ) {
        $this->index_post( $post_id );
    }
}

This would reduce index_post() calls from 20–50 per product to just 1 — no new settings needed, no breaking changes, and it works for both manual edits and bulk imports.

Would the team consider this approach?

2 Likes

Hi @Faradei ,

This seems like a good enhancement.

We will look into it. Did you try this code on your site, and does it work?

Regards,
Jenn

1 Like