Chunking & Storage

Storing Vectors: Your Real Options

⏱ 13 min

Let’s state this plainly before going any further: there is no official WordPress vector storage solution. No core library, no plugin endorsed by the AI team, nothing in the “AI Building Blocks for WordPress” initiative addresses where embeddings actually live once you’ve generated them. If you’ve seen a tutorial or plugin claiming to be “the” official WordPress vector store, it isn’t, this is genuinely custom-implementation territory, and this lesson gives you the real, honest options instead of a made-up one.

What you'll learn in this lesson
Why there's no official answer here
What the Abilities API and PHP AI Client SDK do and don't cover.
Option A: a custom database table
Storing chunks and embeddings yourself, searched with brute-force PHP math.
Option B: an external vector database
What Pinecone, Qdrant, Weaviate, and Postgres pgvector actually are, and when they're worth the added infrastructure.
How to choose
The real factor that decides between them: your content volume, not your ambition.
Prerequisites

Lesson 2’s embedding generation and Lesson 3’s chunking. This lesson decides where the output of both actually lives before Lesson 5 writes the real table schema.

Step 1: Why WordPress genuinely has no answer here

The Abilities API standardizes exposing actions to AI clients. The PHP AI Client SDK standardizes calling AI providers. Neither one, nor anything else shipped by the WordPress AI team as of this writing, standardizes where a generated vector should be stored or how it should be searched. That’s not an oversight you’re missing, it’s a real gap. Everyone building RAG on WordPress today is solving storage themselves, and you should be skeptical of anything claiming otherwise.

For most WordPress sites, a plain custom database table holding each chunk’s text alongside its embedding, searched with cosine similarity computed in PHP at query time, is entirely viable. No new infrastructure, no new service to operate, nothing beyond what a WordPress developer already knows: dbDelta(), $wpdb, standard rows.

The embedding itself gets stored as JSON in a LONGTEXT column (WordPress has no native vector column type), decoded back into a PHP array whenever it’s compared. Lesson 5 builds this table and its schema in full. The tradeoff is search speed: comparing a query vector against every stored row’s vector, one at a time, in a PHP loop, is O(n) work per search. For a site with hundreds or low thousands of chunks this is comfortably fast. For a site with hundreds of thousands of chunks, every search becomes a meaningfully expensive loop, and that’s the point where Option B starts to matter.

Step 3: Option B, an external vector database

For sites with a genuinely large volume of content, dedicated vector databases exist specifically to make similarity search fast at scale, using indexing structures (approximate nearest neighbor algorithms) that avoid comparing against every stored vector on every query. The well-known, real options include:

External vector storage options
OptionWhat it is
PineconeA managed, hosted vector database built specifically for similarity search at scale.
QdrantAn open-source vector database, self-hostable or available managed.
WeaviateAn open-source vector database with built-in hybrid (keyword plus vector) search support.
Postgres with pgvectorAn extension adding vector similarity search directly to a Postgres database you may already run, rather than adopting an entirely new datastore.

Each of these is a real, independently-operated piece of infrastructure, not a WordPress plugin, and integrating with one from a WordPress plugin means calling its API (usually over HTTP) from your PHP code the same way you’d call any external service, authenticating, sending vectors, and querying by similarity through that service’s own client rather than through anything WordPress-specific. This course doesn’t hand you integration code for a specific one of these, since the right client library and its exact current API are a decision you should make and verify at the time you actually need this, not something to copy from a course written months earlier. What matters here is knowing honestly that these exist, what problem they solve, and that reaching for one is an infrastructure decision, not a WordPress one.

Step 4: How to actually choose

Choosing between Option A and Option B
Chunk count in the low thousands or fewer
Option A. A PHP loop over a few thousand rows on a search request is genuinely fast enough, and you avoid operating a second piece of infrastructure entirely.
Chunk count in the tens of thousands or more, or sub-second search at real scale required
Option B starts to matter. Brute-force PHP comparison across that many rows on every request will show up as real, user-visible latency.
Unsure which you'll need
Start with Option A. It's the entire subject of the next lesson, and migrating stored chunks and embeddings to an external vector database later is a data export problem, not a rewrite of your chunking or retrieval logic.

The honest reality for the overwhelming majority of WordPress sites building an internal knowledge base or documentation assistant is that Option A is not a compromise, it’s simply the right amount of infrastructure for the content volume involved.

Don't adopt Option B before you've measured a real problem

It’s tempting to reach for a dedicated vector database up front because it sounds more “production-grade.” In practice this adds a new service to authenticate against, pay for, monitor, and keep in sync, for a performance problem you don’t have yet on a site with a few thousand chunks. Build Option A first, measure actual search latency against your real content volume, and only move to Option B once you’ve confirmed brute-force comparison is genuinely too slow for your traffic, not because it seems more impressive.

Test it: estimate your own chunk count

Before the next lesson builds a real table, get a rough sense of what you’re actually storing for:

wp-env run cli wp eval '
$count = wp_count_posts( "post" )->publish;
echo "Published posts: {$count}\n";
echo "Estimated chunks at ~5 chunks/post: " . ( $count * 5 ) . "\n";
'

If that estimated chunk count lands in the low thousands or fewer, Option A, the subject of the next two lessons, is the right amount of engineering for your site.

Recap

There is no official WordPress vector storage solution, and treating any specific plugin as “the” official one is a mistake. Option A, a custom dbDelta() table storing chunk text and embeddings with brute-force cosine similarity computed in PHP, is genuinely viable for small-to-medium sites and is what this course builds. Option B, an external vector database like Pinecone, Qdrant, Weaviate, or Postgres with pgvector, exists for sites with real scale, and is worth adopting once you’ve measured that brute-force search is actually too slow, not before.

Resources & further reading

← Chunking Strategies for WordPress Content Building a Custom Table for Embedding Storage →