SOLVED: 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

Hi @itchycode ,

yes it work

1 Like

Hi @itchycode,

Small update — the debounce approach works correctly for manual edits and small admin operations, but I’m still hitting issues on larger imports, so I’m keeping the indexer disabled during CSV imports for now while I look for a better solution.

What I’ve found so far on my setup (mirater.ua — WooCommerce CSV Importer, Bricks 2.2, ~500 products per import):

The debounce itself works as intended. I confirmed it via custom logging: handle_post_meta_update gets called 20–50 times per product, but index_post() now runs only once per post ID per request. Savings are real (e.g. 7 meta updates → 1 unique post indexed, saved: 6 redundant calls).

But the debounce doesn’t help on large imports, because WooCommerce doesn’t batch product saves within a single request. Every CSV row is processed as a separate Action Scheduler job (as_async_request_queue_runner), so each request only touches 1 product. There’s nothing to debounce across — each request contains exactly one post ID. The per-request savings drop to zero.

The real bottleneck on larger imports isn’t the indexer itself, it’s the cumulative cost. Even with debounce active, index_post() still runs once per product × 500 products, serially through Action Scheduler with concurrency=1. On my server index_post() averages ~150ms per product, which adds ~75 seconds just for indexing — on top of all the other per-save overhead (GLA sync, Polylang, LSCWP purges, etc.).

What I’m currently doing as a workaround: I detect WC import context (woocommerce_do_ajax_product_import / as_async_request_queue_runner) and completely skip index_post() during import, accumulate post IDs in a transient, then run a single bulk reindex via Action Scheduler after the import finishes. This works but feels fragile.

Suggestion for the core fix: in addition to the shutdown-debounce you’re planning, it would help if Bricks also detected doing_action( 'woocommerce_product_import_before_import' ) / Action Scheduler import runners and either fully suspended indexing (with a single bulk run after), or at least added a filter like bricks/query_filters/skip_indexing that plugins/site owners can hook into.

Hi @Faradei

Thanks for your update. Yes, we will implement the performance improvement logic for the debounce index_post for a single request.

Regarding your skip indexing request, this seems to be back to the question I asked in February.

We’ve addressed this in Bricks 2.3.3, now available as a one-click update in your WordPress Dashboard.

Please read the changelog entry before updating, and let us know if you experience any issues.

This is a very detailed analysis. Adding a hook to programmatically pause the indexer during bulk imports would definitely be a huge performance win for larger WooCommerce sites.

@itchycode Seems like, he already mention above.