WP Vector Search
WordPress plugin that enhances search with vector similarity and BM25 hybrid search, powered by php-vector-store
by Mauricio Perera · github.com/mauricioperera/wp-vector-search · website
★ 0stars
0forks
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/mauricioperera/wp-vector-search/archive/refs/heads/master.zipWordPress plugin that enhances the native search with vector similarity and BM25 hybrid search, powered by php-vector-store.
How it works
- BM25 text indexing happens automatically when posts are published/updated
- Embeddings are pushed externally via REST API (you bring your own embedding pipeline)
- Search combines both signals using Reciprocal Rank Fusion (RRF) or weighted scoring
WordPress Content → BM25 Index (automatic)
→ Vector Store (via REST API) ← Your embedding pipeline
(OpenAI, Ollama, etc.)
User searches → Hybrid fusion (BM25 + Vector) → Reranked results
Features
- Zero-dependency vector search — pure PHP, no extensions needed
- Hybrid search — combines semantic (vector) + keyword (BM25) relevance
- Native WP integration — hooks into
pre_get_poststo enhance the default search - Shortcode —
[vector_search]for a dedicated semantic search widget - REST API — push embeddings from any external pipeline
- Int8 quantization — 4x storage reduction with negligible accuracy loss
- Admin dashboard — statistics, settings, one-click BM25 reindex
Requirements
- PHP 8.1+
- WordPress 6.0+
- Composer
Installation
cd wp-content/plugins
git clone https://github.com/MauricioPerera/wp-vector-search.git
cd wp-vector-search
composer install
Activate from Plugins in wp-admin.
Configuration
Go to Settings → Vector Search in wp-admin:
| Setting | Default | Description |
|---|---|---|
| Vector Dimensions | 384 | Must match your embedding model |
| Quantized Store | On | Int8 quantization (4x smaller) |
| Hybrid Mode | RRF | rrf or weighted |
| Vector Weight | 0.5 | Weight for vector similarity (weighted mode) |
| Text Weight | 0.5 | Weight for BM25 text score (weighted mode) |
| Enhance native search | On | Hook into WordPress search |
REST API
Push Embeddings
# Single embedding
curl -X POST https://yoursite.com/wp-json/wp-vector-search/v1/embeddings \
-H "X-WPVS-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"post_id": 123, "vector": [0.1, 0.2, ...]}'
# Batch
curl -X POST https://yoursite.com/wp-json/wp-vector-search/v1/embeddings/batch \
-H "X-WPVS-API-Key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"items": [{"post_id": 123, "vector": [...]}, {"post_id": 456, "vector": [...]}]}'
Search
# Text-only (BM25)
curl "https://yoursite.com/wp-json/wp-vector-search/v1/search?text=machine+learning&limit=10"
# Hybrid (vector + text)
curl -X GET "https://yoursite.com/wp-json/wp-vector-search/v1/search" \
-d '{"text": "machine learning", "vector": [0.1, 0.2, ...], "limit": 10}'
Other Endpoints
DELETE /wp-json/wp-vector-search/v1/embeddings/{post_id} — Remove embedding
GET /wp-json/wp-vector-search/v1/stats — Index statistics
POST /wp-json/wp-vector-search/v1/reindex — Trigger BM25 reindex
Shortcode
[vector_search placeholder="Search our knowledge base..." limit="10"]
Renders a search form with live results via AJAX. Works with BM25-only if no embeddings are available.
Hooks & Filters
// Customize which post types are indexed
add_filter( 'wpvs_indexable_post_types', function ( $types ) {
$types[] = 'product'; // Add WooCommerce products
return $types;
} );
// Modify text before BM25 indexing
add_filter( 'wpvs_index_text', function ( $text, $post_id ) {
// Add custom fields to searchable text
$text .= ' ' . get_post_meta( $post_id, 'custom_field', true );
return $text;
}, 10, 2 );
// React to search events
add_action( 'wpvs_search_performed', function ( $query, $results ) {
// Log searches, analytics, etc.
}, 10, 2 );
// React to indexing events
add_action( 'wpvs_post_indexed', function ( $post_id, $vector ) {
// Trigger re-embedding, sync, etc.
}, 10, 2 );
Example: External Embedding Pipeline
With OpenAI (Python)
import openai, requests
# Generate embedding
response = openai.embeddings.create(
model="text-embedding-3-small",
input="Your post content here"
)
vector = response.data[0].embedding
# Push to WordPress
requests.post(
"https://yoursite.com/wp-json/wp-vector-search/v1/embeddings",
headers={"X-WPVS-API-Key": "YOUR_KEY"},
json={"post_id": 123, "vector": vector}
)
With n8n
- Trigger: WordPress webhook on post publish
- HTTP Request: Fetch post content
- OpenAI node: Generate embedding
- HTTP Request: POST to
/wp-json/wp-vector-search/v1/embeddings
Architecture
wp-vector-search/
├── wp-vector-search.php # Plugin bootstrap
├── includes/
│ ├── class-plugin.php # Singleton, initializes all components
│ ├── class-indexer.php # BM25 text indexing on save_post
│ ├── class-search.php # pre_get_posts hook for native search
│ ├── class-rest-api.php # REST API endpoints
│ ├── class-admin.php # Settings page & dashboard
│ └── class-shortcode.php # [vector_search] shortcode
├── assets/
│ ├── css/admin.css # Admin styles
│ └── js/search-block.js # Frontend search widget
└── templates/
└── search-results.php # Overridable result template
License
GPL-2.0-or-later