How a bad custom WP_Query can wreck your site

Got a call the other day from a new client. Their WooCommerce shop had a pretty hefty catalog, and it was timing out. Pages weren’t just slow, they were falling over. The main shop page was the worst of it. The previous dev was long gone, naturally.

You see this a lot. When a site slows down, the first instinct is to blame the host or throw more caching at it. My first thought was the caching layers too, maybe a CDN would help. But that’s a band-aid. Caching helps logged-out users, and here the admin area was crawling and logged-in customers were still getting hammered. So the problem was lower down. It’s almost always a bad query.

Finding the rogue query

After about ten minutes of digging, I found the culprit in the theme’s functions.php file. The old dev needed to hide a product category from the main shop page, which is a reasonable request. To do it, they reached for the pre_get_posts action hook. It’s powerful, but dangerous if you don’t know what you’re doing.

Here is the code they used:

function ahmed_exclude_category_from_shop( $query ) {
    // This is the WRONG way to do it.
    $query->set( 'tax_query', array(
        array(
            'taxonomy' => 'product_cat',
            'field'    => 'slug',
            'terms'    => 'uncategorized',
            'operator' => 'NOT IN',
        ),
    ) );
}
add_action( 'pre_get_posts', 'ahmed_exclude_category_from_shop' );

See the problem? This function runs on every single post query across the entire site. The main shop, yes, but also admin screens, menus, sidebars, and AJAX requests. It forced WordPress to add a complex tax query where it didn’t belong, which ground the database to a halt. Carl Alexander explains the underlying concept in detail in his post at https://carlalexander.ca/wordpress-adventurous-wp-query-class/.

The right way to modify the main query

The fix is to be specific. You have to tell WordPress exactly which query you want to modify, and you do that with conditional checks. Here we only want to change the main query, on the front end, on the shop page. Everything else stays untouched.

function ahmed_exclude_category_from_shop( $query ) {
    // Check if we're on the front-end, in the main query, on the shop page.
    if ( ! is_admin() && $query->is_main_query() && is_shop() ) {
        $query->set( 'tax_query', array(
            array(
                'taxonomy' => 'product_cat',
                'field'    => 'slug',
                'terms'    => 'uncategorized',
                'operator' => 'NOT IN',
            ),
        ) );
    }
}
add_action( 'pre_get_posts', 'ahmed_exclude_category_from_shop' );

This version is safe and surgical. It targets only the query it’s meant to and leaves everything else alone. The difference was immediate: page load times went from 20 seconds to under 2, and the admin was responsive again.

What to check before touching a query

WP_Query is the engine of WordPress, and pre_get_posts gives you direct access to the ignition. That’s worth respecting. Before you modify a query, ask yourself:

  • Is this the main query for the page? Use is_main_query().
  • Should this run in the admin? If not, use ! is_admin().
  • Is there a more specific conditional, like is_shop() or is_category(), that I can use?

For secondary content, like a “Related Products” block, don’t use this hook at all. Instantiate a new WP_Query() object instead. It keeps things clean, and it means picking the tool that fits the job rather than the most powerful one available.

Look, this stuff gets complicated fast. If you’re tired of debugging someone else’s mess and just want your site to work, drop my team a line. We’ve probably seen it before.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.