WordPress Search Not Working? Fix No Results & Broken Queries
A customer wrote in last week convinced their WordPress site was "broken" because searching for a product that was clearly on the homepage returned nothing. It wasn't broken - the search was just doing exactly what WordPress tells it to do by default, which surprises almost everyone the first time they hit it. Here's how to actually diagnose and fix a search that's returning zero results, stale results, or a blank page.
Start With What You're Actually Seeing
"Search isn't working" covers a few different failures, and each one points to a different cause:
- Zero results for content that exists - usually a query scope problem (post type, post status) or a broken index.
- The search results page 404s - a permalinks or rewrite rule issue.
- Search works for some terms but not others - almost always a full-text index or stopword problem.
- Search worked yesterday, not today - check recent plugin updates, caching, or a WAF/ModSecurity rule change.
Figure out which bucket you're in before you start changing settings - it saves a lot of wasted time.
Cause 1: Custom Post Types Are Invisible to Search by Default
This is the single most common reason "search finds nothing" on a site that clearly has content. WordPress's default search (WP_Query with the s parameter) only searches post types that were registered with 'exhibit_ui' => true and 'exclude_from_search' => false. Products, portfolio items, listings, staff profiles - any custom post type from a theme or plugin - can silently sit outside the search index unless it was registered correctly.
Check it fast: go to Settings > Search if your theme exposes one, or just test with a plugin like Query Monitor to see the actual WP_Query arguments running on the search page. If post_type is locked to post and page, that's your answer.
Fix it by hooking into pre_get_posts in your child theme's functions.php:
function gwu_search_include_cpts( $query ) {
if ( $query->is_search() && ! is_admin() && $query->is_main_query() ) {
$query->set( 'post_type', array( 'post', 'page', 'product', 'listing' ) );
}
}
add_action( 'pre_get_posts', 'gwu_search_include_cpts' );
Swap product/listing for your actual post type slugs. If you're running WooCommerce, don't do this manually - WooCommerce already registers its own search behaviour and stacking a custom filter on top can cause duplicate or conflicting queries. See the WooCommerce section below instead.
Cause 2: A Caching Plugin or CDN Is Serving a Stale Result Page
Search result URLs (/?s=widget or /search/widget/) are dynamic by nature - every unique query string is technically a different page. Some caching plugins and CDN rules cache these anyway, which means the first person who searched "widget" gets a fresh, correct result, and everyone after gets whatever was cached at that moment - including zero results if that first search happened to be a typo.
In LiteSpeed Cache, WP Rocket, or W3 Total Cache, confirm query-string URLs are excluded from the page cache. In LiteSpeed Cache specifically, check Cache > Excludes > Do Not Cache URIs and add:
/?s=*
/search/*
If you're behind Cloudflare, go to Caching > Cache Rules and add a rule that bypasses cache when the URI contains /?s= or matches /search/. Skipping this step is the reason search "randomly" works for some visitors and not others.
Cause 3: The Theme's Search Template Is Broken or Missing
If search.php (or the block-theme equivalent) is missing, misconfigured, or has a broken loop, WordPress falls back to index.php, which may not even display the query results - it might just show your latest posts instead, which looks exactly like "search returns nothing relevant."
Quick check: switch to a default theme like Twenty Twenty-Four temporarily and repeat the same search. If it works there, the problem is in your active theme's template, not WordPress itself. Look for a stray have_posts() check that's testing the wrong query object, or a missing the_search_query() call that's breaking the form.
Cause 4: The Full-Text Index Needs Rebuilding
If you're using a plugin like SearchWP, Relevanssi, or WooCommerce's product search, they build their own index tables (usually named something like wp_relevanssi or wp_searchwp_index) separately from MySQL's native content. After a migration, a bulk import, or a database restore, that index doesn't rebuild itself - it just sits there stale or empty.
Most of these plugins have a manual reindex button under their settings page. If you have WP-CLI access via SSH or cPanel Terminal, it's usually faster:
# Relevanssi
wp relevanssi index
# SearchWP (if the CLI add-on is active)
wp searchwp index rebuild
Run this any time content volume changes significantly - after a large CSV import, after restoring from backup, or after a plugin update that touches the indexing schema.
Cause 5: ModSecurity or a WAF Rule Is Blocking the Query String
This one shows up right after a migration to a new host or a security plugin update: search works locally or in a staging environment but 403s or silently fails in production. ModSecurity's OWASP core rule set sometimes flags search terms containing SQL-looking characters (quotes, UNION, SELECT, even innocuous words that overlap SQL syntax) as an injection attempt and blocks the request outright.
In cPanel, check WHM > ModSecurity Tools or ask your host for the Apache error log entry - it'll show a rule ID like ModSecurity: Access denied with code 403 (phase 2). ... [id "942100"]. Once you have the rule ID, you can whitelist it for just the search endpoint rather than disabling ModSecurity site-wide:
<LocationMatch "^/search/">
SecRuleRemoveById 942100
</LocationMatch>
Never disable ModSecurity globally to fix this - that's swapping a search bug for a real security hole.
WooCommerce Product Search: A Special Case
WooCommerce search has its own quirks worth calling out separately:
- Out-of-stock products hidden from search - check WooCommerce > Settings > Inventory > Hide out of stock items from the catalog. This setting removes them from search too, not just category pages.
- Variations not matching - by default, WooCommerce searches parent product titles, not variation attributes like size or color. A search for "blue" won't find a shirt that's only tagged blue as a variation unless you add a plugin like WooCommerce Search Variations by SKU or configure SearchWP to index variation meta.
- SKU search not working - native WooCommerce search doesn't match SKUs unless you add a filter. Use the free "Search by SKU for WooCommerce" plugin or hook
posts_whereyourself.
Step-by-Step Fix Checklist
| Step | What to Check | Tool |
|---|---|---|
| 1 | Which failure mode - zero results, 404, blank page | Manual test |
| 2 | Post type included in search query | Query Monitor |
| 3 | Caching plugin excludes ?s= and /search/ | Cache plugin settings |
| 4 | Theme search template functioning | Switch to default theme |
| 5 | Search plugin index up to date | WP-CLI or plugin reindex button |
| 6 | ModSecurity/WAF not blocking the request | Apache/WHM error log |
Prevention
Once search is working, keep it that way:
- Schedule a monthly reindex cron job if you're on SearchWP or Relevanssi and import content regularly.
- Add search-related URLs to your cache exclusion list before launch, not after someone complains.
- Test search explicitly after every migration or restore - it's easy to miss because the homepage looks fine.
- Register custom post types with
exclude_from_search => falsefrom day one instead of patching it in later.
Frequently asked questions
Why does WordPress search find pages but not products or custom content?
By default, WP_Query's search only includes post types registered with exclude_from_search set to false. Products, portfolios, and other custom post types are often excluded unless the theme or plugin explicitly adds them, or you add a pre_get_posts filter to include them yourself.
Why does search work for some visitors but not others?
This is almost always a caching issue. Page caching plugins or a CDN can cache the first version of a dynamic search-results URL and serve that same cached page to everyone afterward. Exclude /?s= and /search/ URLs from your cache rules.
I restored from a backup and now search returns nothing. Why?
If you're using a search plugin like SearchWP or Relevanssi, its index table is separate from your content and doesn't rebuild automatically after a restore or migration. Run the plugin's manual reindex, or wp relevanssi index / wp searchwp index rebuild over WP-CLI.
Search worked before a site migration and now it 403s. What changed?
Check for a ModSecurity or WAF rule blocking the search query string, especially if search terms contain characters that resemble SQL syntax. Look for the rule ID in your host's Apache error log and whitelist it for the search endpoint rather than disabling ModSecurity entirely.
Can I make WooCommerce search match SKUs and product variations?
Not out of the box. Native WooCommerce search only matches product titles and content by default. Use a plugin like Search by SKU for WooCommerce, or index variation attribute meta with SearchWP, to make SKU and variation searches work.