WP VIP Search
Part of the Sidecar Services catalog.
What it does
wpvip-search mirrors WP VIP Enterprise Search locally. VIP's Enterprise Search runs ElasticPress against an Elasticsearch backend, so this preset gives a WP VIP project the same engine on your machine. Add it when you are developing a VIP site that uses Enterprise Search and want queries served by a real Elasticsearch instance rather than the WordPress default.
Use this preset rather than the generic elasticsearch one when the project is a VIP site: it pins the version VIP runs and injects the VIP and ElasticPress env vars.
How it works
The preset pins docker.elastic.co/elasticsearch/elasticsearch:7.10.2. VIP pins the 7.10.x line, so this preset matches that version rather than the generic elasticsearch 8.x preset. It listens on container port 9200, runs as a single node with security disabled (discovery.type=single-node, xpack.security.enabled=false) and a 512m heap, and persists its index in a named volume mounted at /usr/share/elasticsearch/data.
It gets a browser UI: the host port is auto-allocated from the 7000 to 7999 range and de-conflicted across all projects.
wdg my-site service add wpvip-search
wdg my-site service listRead the browser URL from the service list output.
How it integrates with the local WordPress container
Adding the sidecar injects these env vars into the WordPress container:
| Variable | Value |
|---|---|
EP_HOST | http://wdg-my-site-wpvip-search:9200 (the @HOST token resolved at add-time) |
VIP_ELASTICSEARCH_ENDPOINTS | http://wdg-my-site-wpvip-search:9200 |
VIP_ELASTICSEARCH_USERNAME | empty |
VIP_ELASTICSEARCH_PASSWORD | empty |
WordPress reaches the engine over wdg-network at wdg-my-site-wpvip-search:9200, never the host port. The host port exists only for your browser. The credentials arrive empty because the local node runs with security disabled, but do not pass them through as-is: see step 1 below.
Unlike the other search presets, this one needs project-side wiring. The sidecar provides the engine and the connection env only. The project must still:
- install ElasticPress /
vip-go-mu-pluginsin its codebase, - bridge the injected env vars to the matching PHP constants, and
- build the Elasticsearch indexes.
Skipping any of those fails silently. The container is healthy and the engine answers from PHP, so nothing in wdg status, the logs, or a page load tells you the integration is inert.
Setup
1. Bridge the env vars to PHP constants
VIP and ElasticPress read PHP constants, not env vars, so the project maps one to the other. On a wdg-created project this goes in projects/<name>/config/wp-config-custom.php; on a project that manages its own config, use wp-config.php or an early mu-plugin.
if ( ! defined( 'VIP_ENABLE_VIP_SEARCH' ) ) {
define( 'VIP_ENABLE_VIP_SEARCH', true );
}
if ( ! defined( 'VIP_ELASTICSEARCH_ENDPOINTS' ) ) {
define( 'VIP_ELASTICSEARCH_ENDPOINTS', [
getenv( 'VIP_ELASTICSEARCH_ENDPOINTS' ) ?: 'http://wdg-my-site-wpvip-search:9200',
] );
}
if ( ! defined( 'VIP_ELASTICSEARCH_USERNAME' ) ) {
define( 'VIP_ELASTICSEARCH_USERNAME', getenv( 'VIP_ELASTICSEARCH_USERNAME' ) ?: 'wdg-local' );
}
if ( ! defined( 'VIP_ELASTICSEARCH_PASSWORD' ) ) {
define( 'VIP_ELASTICSEARCH_PASSWORD', getenv( 'VIP_ELASTICSEARCH_PASSWORD' ) ?: 'wdg-local' );
}
if ( ! defined( 'FILES_CLIENT_SITE_ID' ) ) {
define( 'FILES_CLIENT_SITE_ID', 1 );
}Guard every one with ! defined() so the real VIP platform values win in production.
Three details in that snippet are load-bearing:
VIP_ELASTICSEARCH_ENDPOINTS must be an array. The sidecar injects it as a plain string, so wrap it.
VIP_ELASTICSEARCH_USERNAME and VIP_ELASTICSEARCH_PASSWORD must be non-empty. Automattic\VIP\Search\Search::are_es_constants_defined() (mu-plugins/search/includes/classes/class-search.php) returns true only when the endpoints array and a truthy username and a truthy password are all present, and mu-plugins/search/search.php never reaches its do_action( 'vip_search_loaded' ) otherwise. Defining the injected empty strings is therefore the same as defining nothing, which is why the fallback supplies a placeholder. The node ignores the Authorization header with security disabled, so any truthy value works.
FILES_CLIENT_SITE_ID selects the index name -- the vip-1 in vip-1-post-1. Without it ElasticPress has no index to target.
2. Restart
wdg my-site restartA restart is required, not optional. The project docker-compose.yml mounts config/wp-config-custom.php as a single-file bind mount, which pins to the host file's inode at container start. Editors that save atomically give the file a new inode, so the container keeps serving the old config until it is recreated.
3. Build the indexes
wdg my-site wp vip-search index --setup--setup drops and recreates the indexes, and the run time scales with the content set. Until it finishes, searches return nothing even with everything else wired correctly.
4. Verify
wdg my-site wp eval 'var_dump( did_action( "vip_search_loaded" ) );'1 means the module loaded. 0 means the constants are not satisfying the gate in step 1, almost always an empty credential or a string instead of an array. Confirm the engine side separately:
curl -s "http://localhost:7000/_cat/indices?v" # host port, for your browserRows named vip-1-post-1 and friends mean step 3 landed.
Project-side wiring required
Adding the sidecar does not install the plugins, write the bridge, or build the indexes. Without all four steps above, WordPress can reach the engine but will not use it for search, and nothing reports an error.
Add and remove
wdg my-site service add wpvip-search
wdg my-site service remove wpvip-search # keeps the data volume
wdg my-site service remove wpvip-search --purge # also deletes the data volume