AI Search: WordPress Search with AI Embeddings

Well, it’s been a while since my last blog post. But hey, maybe we should only write when we actually have something worth saying, right?

This time, I do have something to share: I’ve been working on a new approach to WordPress search that uses AI and embeddings to understand the meaning behind search queries, not just the keywords.

Let me show you how it works, and why it might completely change how your visitors interact with your content. BAsically, I built a new plugin called AI Search that brings intelligent, semantic search to WordPress.

What Are Embeddings?

Embeddings turn text into vector representations that capture semantic meaning. This allows us to compare how similar two texts are, even if they don’t share the same exact words.

Then, when a user searches, their query is also embedded and compared to your content using cosine similarity.

Here’s a visual explanation (at least, it helped me understanding the concept):

AI embeddings

src: https://arize.com/blog-course/embeddings-meaning-examples-and-how-to-compute/

Those values aren’t absolute, right? So we should have a way to define how close we want our search query to be considered in our AI results – so I needed to create a method to define what is similarity in this context:

private function calculate_similarity( $a, $b ) {
    $dot_product = array_sum( array_map( fn($x, $y) => $x * $y, $a, $b ) );
    $magnitude_a = sqrt( array_sum( array_map( fn($x) => $x ** 2, $a ) ) );
    $magnitude_b = sqrt( array_sum( array_map( fn($x) => $x ** 2, $b ) ) );

    return $dot_product / ( $magnitude_a * $magnitude_b );
}

Replacing the Search Query: From Keyword to Meaning Matching

Out of the box, classic search is basic – not only in WordPress, in general, the search tools look for keywords. When a user types a query, WordPress looks for that exact word or phrase in post titles or content using a simple LIKE '%searchterm%' SQL clause. While this works for surface-level matching, it has major limitations:

  • It can’t understand synonyms or variations (e.g., “car” vs. “vehicle”)
  • It doesn’t grasp intent or context
  • It returns results based on text presence, not text relevance

Let’s say you have a post titled “How to Start a Blog”. A user searching for “create a website” won’t see that post, even though it’s exactly what they need.

With AI Search, we replace the default search behaviour entirely. Here’s the flow:

  1. The plugin hooks into the SQL query via the posts_request filter.
  2. It detects if the request is a search (is_search), and bypasses admin queries.
  3. It converts the user’s search term into an embedding vector using OpenAI.
  4. It loops through all published posts with saved embeddings.
  5. For each post, it calculates the cosine similarity between the query and the content.
  6. It filters out posts below the similarity threshold.
  7. It returns a custom SQL query that retrieves only relevant post IDs, in order of semantic relevance.

Here’s the code in action (feel free to comment and recommend another approach):

public function custom_search_query( $sql, $query ) {
    if ( ! $query->is_search || is_admin() ) {
        return $sql;
    }

    $search_query = sanitize_text_field( get_search_query() );
    $query_embedding = $this->get_embedding( $search_query );

    if ( ! $query_embedding ) {
        return $sql;
    }

    $posts = get_posts([
        'numberposts' => -1,
        'post_type'   => 'any',
        'post_status' => 'publish',
        'meta_key'    => '_ai_search_embedding',
    ]);

    $similarities = [];

    foreach ( $posts as $post ) {
        $embedding_json = get_post_meta( $post->ID, '_ai_search_embedding', true );
        if ( empty( $embedding_json ) ) {
            continue;
        }

        $embedding = json_decode( $embedding_json, true );
        $similarity = $this->calculate_similarity( $query_embedding, $embedding );

        if ( $similarity >= $this->similarity_threshold ) {
            $similarities[ $post->ID ] = $similarity;
        }
    }

    arsort( $similarities );

    $sorted_ids = array_keys( $similarities );

    if ( empty( $sorted_ids ) ) {
        return "SELECT * FROM {$GLOBALS['wpdb']->posts} WHERE 1=0"; // No match
    }

    $ids = implode( ',', array_map( 'intval', $sorted_ids ) );
    return "SELECT * FROM {$GLOBALS['wpdb']->posts} WHERE ID IN ($ids) ORDER BY FIELD(ID, $ids)";
}

This works under the hood. You don’t need to change your template files, query_posts, or WP_Query calls, the filter intercepts all search queries automatically.

Why This Matters

Well if you run a content-heavy site – a blog, knowledge base, product catalog, or membership platform. This upgrade will make search feel instant, intelligent, and intuitive.

Users find what they mean, not just what they typed.


Try AI Search

The plugin is free and open-source, built with developers in mind. It uses native WordPress functions, clean PHP, and integrates seamlessly with your existing site. Let me know if you would like to see this working on other environments beyond WordPress.


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *