How7o
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Reading: How to Include SKU in WooCommerce Search
Share
How7oHow7o
Font ResizerAa
  • OS
Search
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Follow US
© 2024–2026 How7o. All rights reserved.
How7o > Free Laravel, PHP, WordPress & Server Tutorials > Web Development > How to Include SKU in WooCommerce Search
Web Development

How to Include SKU in WooCommerce Search

how7o
By how7o
Last updated: May 10, 2026
8 Min Read
WooCommerce SKU search — posts_search filter injecting SKU-matched product IDs
SHARE

By default, woocommerce sku search fails — a customer searching for a product code like SHOE-002-RED gets no results. WordPress’s core search only scans post_title and post_content; SKUs live in post meta (_sku) and stay invisible. The fix is a posts_search filter that runs a parallel meta query for SKU matches and OR-merges the result IDs into the main search SQL. This guide walks through the snippet, its caveats, and when to consider an external search instead.

Contents
  • TL;DR
  • Why the default search misses SKUs
  • How the filter works
  • Scoping to product queries only
  • The brittle bit
  • When to skip this and use external search
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-04-23 on WooCommerce 9.x with WordPress 6.5. Originally published 2023-04-01, rewritten and updated 2026-04-23.

TL;DR

add_filter( 'posts_search', 'how7o_include_sku_in_search', 999, 2 );

function how7o_include_sku_in_search( $search, $query_vars ) {
    global $wpdb;

    if ( empty( $query_vars->query['s'] ) ) {
        return $search;
    }

    $term = $query_vars->query['s'];

    $posts = get_posts( array(
        'post_type'      => 'product',
        'posts_per_page' => -1,
        'fields'         => 'ids',
        'meta_query'     => array(
            array(
                'key'     => '_sku',
                'value'   => $term,
                'compare' => 'LIKE',
            ),
        ),
    ) );

    if ( empty( $posts ) ) {
        return $search;
    }

    $id_list = implode( ',', array_map( 'absint', $posts ) );
    $search  = str_replace(
        'AND (((',
        "AND ((({$wpdb->posts}.ID IN ({$id_list})) OR (",
        $search
    );

    return $search;
}

Why the default search misses SKUs

The core WordPress search assembles a query like:

SELECT * FROM wp_posts
WHERE ...
  AND (((post_title LIKE '%term%') OR (post_content LIKE '%term%')))
  AND ...

No wp_postmeta join means no chance of matching the _sku row. WooCommerce doesn’t extend this by default — SKU-as-searchable is left to developers.

How the filter works

  • posts_search is a filter WordPress applies after it’s built the AND (((title OR content))) fragment.
  • Before the fragment is stitched into the final query, we intercept it.
  • We run a parallel get_posts() against _sku meta with LIKE, collect the matching IDs.
  • We inject those IDs as an OR-clause at the start of the search block: AND ((({posts}.ID IN (...)) OR (title OR content))).
  • The final query matches anything whose ID is in our SKU-match list or whose title/content matches.
woocommerce sku search — posts_search filter injects meta-queried IDs into the title/content SQL

Scoping to product queries only

add_filter( 'posts_search', function ( $search, $query ) {
    if ( ! is_search() || $query->get( 'post_type' ) !== 'product' ) {
        return $search;
    }

    // ... (filter body as above)
    return $search;
}, 999, 2 );

The base snippet fires on every search, including post and page searches — wasteful even though the meta_query is scoped to products. Wrapping with is_search() plus the post_type check skips non-product searches entirely.

The brittle bit

$search = str_replace( 'AND (((', "AND ((({$wpdb->posts}.ID IN ({$id_list})) OR (", $search );

WordPress generates the search fragment with a distinctive AND ((( prefix, which this str_replace targets. It’s worked for many years but is technically tied to WordPress’s internal SQL generator. If a future WordPress release changes the fragment shape, this str_replace silently stops matching and SKU search stops working — no error, just empty results. Watch for it on major version upgrades (test a SKU search after updating core).

When to skip this and use external search

  • Catalogs over ~10,000 products — the get_posts with -1 scans every SKU on every search. Fine at a few hundred products, slow at tens of thousands.
  • Need typo-tolerance / ranking — “SHOE-002-RED” vs “shoe 002 red” are very different to MySQL’s LIKE; they’re the same to ElasticPress, Algolia, or Meilisearch.
  • Need multi-field fuzzy matching — search against SKU + attribute + category + description with relevance scoring. MySQL LIKE is out of its depth here.

For small catalogs where the native filter works, keep this snippet. For production shops, an external index is the appropriate tool.

Frequently asked questions

Why doesn’t the default woocommerce sku search find products by SKU?

Because WordPress’s core search only scans post_title and post_content. SKUs live in product meta (_sku row in wp_postmeta), which the default LIKE query never touches. Extending the search to match SKUs requires filtering posts_search to inject an OR-clause that also matches products whose meta _sku value contains the term.

Does the filter affect search results on every post type?

It’s scoped with 'post_type' => 'product' inside the meta query, so only products match by SKU. Other post types (posts, pages) still only match by title/content. But the filter itself fires on every search query, so if your theme runs the search form across mixed post types, the meta_query runs every time — harmless but an extra query. For scope, wrap the filter body in is_search() && $query->get('post_type') === 'product'.

Will this include products without an SKU?

The filter only adds matching products with an SKU to the result set; it doesn’t exclude SKU-less products from title/content matches. A search for ‘shoes’ will still match both a product titled ‘Running Shoes’ (no SKU needed) and a product with SKU SHOES-001 via the meta clause — the OR’ing is additive.

Is the str_replace on the SQL safe?

Yes, because AND ((( is a stable string literal in WordPress’s generated search SQL — it marks the start of the search clause group, and the replacement injects our own post-ID list before that. It’s not elegant — it’s a workaround for a filter that gives you the SQL fragment rather than structured data. If WordPress ever changes the literal, the filter silently stops matching. Keep an eye on major WP version changes.

Is there a cleaner approach using pre_get_posts?

You can set the meta_query directly in pre_get_posts, but the catch is that WordPress’s search uses the s parameter to build its own SQL, and combining that with a meta_query results in AND (match title AND sku), not the OR you want. The posts_search filter is the pragmatic path — ugly, works. For a more robust solution, an external search layer (ElasticPress, Algolia, Meilisearch) indexes SKUs as searchable fields natively.

Related guides

  • How to Prepare a %LIKE% SQL Statement in WordPress — the raw $wpdb LIKE mechanics behind WordPress’s search.
  • How to Search Users by Multiple Fields in WordPress — the same “search across multiple fields” problem on the user side.
  • How to Display a Product View Counter in WooCommerce Without a Plugin — another meta-based product enhancement.
  • How to Apply pre_get_posts on Custom Post Types in WordPress — cousin query-modification pattern.

References

WordPress developer reference for posts_search: developer.wordpress.org/reference/hooks/posts_search.

TAGGED:mysqlphpsqlWooCommercewordpress

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
[mc4wp_form]
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article WooCommerce get customer ID from order — WC_Order::get_user_id How to Get the Customer ID from an Order ID in WooCommerce
Next Article WooCommerce remove checkout fields — woocommerce_checkout_fields filter unsetting fields How to Remove Checkout Fields in WooCommerce
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

FacebookLike
XFollow
PinterestPin
InstagramFollow
Most Popular
Laravel Eloquent ORM — a model class mapping to a database table with query methods
Laravel Eloquent ORM: The Complete Guide to Querying Your Database
June 16, 2026
Set vi as the default editor in Ubuntu — a terminal opening the vim editor
How to Set vi (Vim) as the Default Editor in Ubuntu
June 8, 2026
rsync says ALL DONE but files are missing — a terminal showing ALL DONE next to an empty folder
rsync Says “ALL DONE” but Files Are Missing: How to Verify
June 8, 2026
Migrate a website to a new server with rsync — files copying from an old server to a new one over SSH
How to Migrate a Website to a New Server With rsync
June 8, 2026
Bun runtime — faster JS toolkit replacing npm in Laravel projects
How to Install Bun Runtime on Ubuntu (And Use It in a Laravel Project)
May 24, 2026

You Might Also Like

Laravel Eloquent multiple where and orWhere — closure-grouped query snippet with parenthesis highlight
Web Development

How to Combine Multiple where() and orWhere() in Laravel Eloquent

7 Min Read
Laravel Eloquent group by count — Book::groupBy('author') query with bar-chart aggregate icon
Web Development

How to Count Records Grouped By a Column in Laravel Eloquent

7 Min Read
Get the index in a jQuery each loop
Web Development

How to Get the Index in a jQuery .each() Loop

4 Min Read
Dynamically set site title and tagline in WordPress by country
Web Development

How to Dynamically Set Site Title and Tagline in WordPress (By Country)

6 Min Read
How7o

We provide tips, tricks, and advice for improving websites and doing better search.

Tools

  • Age Calculator
  • Word Counter
  • Image Upscaler
  • Password Generator
  • QR Code Generator
  • See all tools→

Pranks

  • Fake Blue Screen Prank
  • Hacker Typer
  • Fake iMessage Generator
  • Windows XP Crash Prank
  • Windows 11 Update Prank
  • See all prank screens →

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service
  • Sitemap
© 2024–2026 How7o. All rights reserved.
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?