PHPackages                             alleyinteractive/es-wp-query - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. alleyinteractive/es-wp-query

ActiveWordpress-plugin[API Development](/categories/api)

alleyinteractive/es-wp-query
============================

Elasticsearch Wrapper for WP\_Query

0.5.2(1y ago)1242.6k↓42.1%28[16 issues](https://github.com/alleyinteractive/es-wp-query/issues)[4 PRs](https://github.com/alleyinteractive/es-wp-query/pulls)GPL-2.0-or-laterPHP

Since May 23Pushed 7mo ago65 watchersCompare

[ Source](https://github.com/alleyinteractive/es-wp-query)[ Packagist](https://packagist.org/packages/alleyinteractive/es-wp-query)[ Docs](https://github.com/alleyinteractive/es-wp-query)[ RSS](/packages/alleyinteractive-es-wp-query/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (6)DependenciesVersions (7)Used By (0)

[![Coding Standards workflow](https://github.com/alleyinteractive/es-wp-query/actions/workflows/coding-standards.yml/badge.svg)](https://github.com/alleyinteractive/es-wp-query/actions/workflows/coding-standards.yml/badge.svg)[![Unit Tests workflow](https://github.com/alleyinteractive/es-wp-query/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/alleyinteractive/es-wp-query/actions/workflows/unit-tests.yml/badge.svg)

Elasticsearch Wrapper for WP\_Query
===================================

[](#elasticsearch-wrapper-for-wp_query)

A drop-in replacement for WP\_Query to leverage Elasticsearch for complex queries.

Warning!
--------

[](#warning)

This plugin is currently in beta development, and as such, no part of it is guaranteed. It works (the unit tests prove that), but we won't be concerned about backwards compatibility until the first release. If you choose to use this, please pay close attention to the commit log to make sure we don't break anything you've implemented.

Instructions for use
--------------------

[](#instructions-for-use)

This is actually more of a library than it is a plugin. With that, it is plugin-agnostic with regards to how you're connecting to Elasticsearch. It therefore generates Elasticsearch DSL, but does not actually connect to an Elasticsearch server to execute these queries. It also does no indexing of data, it doesn't add a mapping, etc. If you need an Elasticsearch WordPress plugin, we also offer a free and open-source option called [SearchPress](https://github.com/alleyinteractive/searchpress).

Once you have your Elasticsearch plugin setup and you have your data indexed, you need to tell this library how to use it. If the implementation you're using has an included adapter, you can load it like so:

```
es_wp_query_load_adapter( 'adapter-name' );

```

If your Elasticsearch implementation doesn't have an included adapter, you need to create a class called `ES_WP_Query` which extends `ES_WP_Query_Wrapper`. That class should, at the least, have a method `query_es()` which executes the query on the Elasticsearch server. Here's an example:

```
class ES_WP_Query extends ES_WP_Query_Wrapper {
	protected function query_es( $es_args ) {
		return wp_remote_post( 'http://localhost:9200/wordpress/post/_search', array( 'body' => json_encode( $es_args ) ) );
	}
}

```

See the [included adapters](https://github.com/alleyinteractive/es-wp-query/tree/master/adapters) for examples and inspiration.

Once you have an adapter setup, there are two ways you can use this library.

The first, and preferred, way to use this library is to instantiate `ES_WP_Query` instead of `WP_Query`. For instance:

```
$q = new ES_WP_Query( array( 'post_type' => 'event', 'posts_per_page' => 20 ) );

```

This will guarantee that your query will be run using Elasticsearch (assuming that the request can and should use Elasticsearch) and you should have no conflicts with themes or plugins. The resulting object (`$q` in this example) works just like WP\_Query outside of how it gets the posts.

The second way to use this library is to add `'es' => true` to your WP\_Query arguments. Here's an example:

```
$q = new WP_Query( array( 'post_type' => 'event', 'posts_per_page' => 20, 'es' => true ) );

```

In one regard, this is a safer way to use this library, because it will fall back on good 'ole `WP_Query` if the library ever goes missing. However, because it depends on the normal processing of WP\_Query, it's possible for a plugin or theme to create conflicts, where that plugin or theme is trying to modify WP\_Query through one of its provided filters (see below for additional details). In that regard, this can be a very unsafe way to use this library.

Regardless of which way you use the library, everything else about the object should work as per usual.

Differences with WP\_Query and Unsupported Features
---------------------------------------------------

[](#differences-with-wp_query-and-unsupported-features)

### Meta Queries

[](#meta-queries)

- **Regexp comparisons are not supported.** The regular expression syntax is slightly different in Elasticsearch vs. PHP, so even if we tried to support them, it would result in a lot of unexpected behaviors. Furthermore, regular expressions are very resource-intensive in Elasticsearch, so you're probably better off just using WP\_Query for these queries regardless.
    - If you try to use a regexp query, ES\_WP\_Query will throw a `_doing_it_wrong()` notice.
- **LIKE comparisons are incongruous with MySQL.** In ES\_WP\_Query, LIKE-comparison meta queries will run a `match` query against the analyzed meta values. This will behave similar to a keyword search and will generally be more useful than a LIKE query in MySQL. However, there are notably differences with the MySQL implementation and ES\_WP\_Query will very likely produce different search results, so don't expect it to be a drop-in replacement.

A note about WP\_Query filters
------------------------------

[](#a-note-about-wp_query-filters)

Since this library removes MySQL from most of the equation, the typical WP\_Query filters (`posts_where`, `posts_join`, etc.) become irrelevant or -- in some extreme situations -- conflicting.

The gist of what happens whn you use `WP_Query( 'es=true' )` is that on `pre_get_posts`, the query vars are sent to a new instance of `ES_WP_Query`. The query vars are then replaced with a simple `post__in` query using the IDs which Elasticsearch found. Because the generated SQL query is far simpler than the query vars would suggest, a plugin or theme might try to manipualte the SQL and break it.

Action/FilterUsing `ES_WP_Query``ES_WP_Query` EquivalentUsing `WP_Query` with `'es' => true``pre_get_posts`No issues`es_pre_get_posts`Potential conflicts`posts_search`N/A`es_posts_search`Should be N/A`posts_search_orderby`N/A`es_posts_search_orderby`Should be N/A`posts_where`N/A`es_query_filter`Potential conflicts`posts_join`N/APotential conflicts`comment_feed_join`N/APotential conflicts`comment_feed_where`N/APotential conflicts`comment_feed_groupby`N/APotential conflicts`comment_feed_orderby`N/APotential conflicts`comment_feed_limits`N/APotential conflicts`posts_where_paged`N/A`es_posts_filter_paged`, `es_posts_query_paged`Potential conflicts`posts_groupby`N/APotential conflicts`posts_join_paged`N/APotential conflicts`posts_orderby`N/A`es_posts_sort`Potential conflicts`posts_distinct`N/APotential conflicts`post_limits`N/A`es_posts_size`, `es_posts_from`Potential conflicts`posts_fields`N/A`es_posts_fields`No issues`posts_clauses`N/A`es_posts_clauses`Potential conflicts`posts_selection`N/A`es_posts_selection`Potential conflicts`posts_where_request`N/A`es_posts_filter_request`, `es_posts_query_request`Potential conflicts`posts_groupby_request`N/APotential conflicts`posts_join_request`N/APotential conflicts`posts_orderby_request`N/A`es_posts_sort_request`Potential conflicts`posts_distinct_request`N/APotential conflicts`posts_fields_request`N/A`es_posts_fields_request`No issues`post_limits_request`N/A`es_posts_size_request`, `es_posts_from_request`Potential conflicts`posts_clauses_request`N/A`es_posts_clauses_request`Potential conflicts`posts_request`N/A`es_posts_request`Potential conflicts`split_the_query`N/APotential conflicts`posts_request_ids`N/APotential conflicts`posts_results`N/A`es_posts_results`No issues`comment_feed_join`N/APotential conflicts`comment_feed_where`N/APotential conflicts`comment_feed_groupby`N/APotential conflicts`comment_feed_orderby`N/APotential conflicts`comment_feed_limits`N/APotential conflicts`the_preview`N/A`es_the_preview`Potential conflicts`the_posts`N/A`es_the_posts`No issues`found_posts_query`N/APotential conflicts`found_posts`N/A`es_found_posts`Potential conflicts`wp_search_stopwords`N/AN/A`get_meta_sql`N/A`get_meta_dsl`N/A`date_query_valid_columns`No issuesNo issues`get_date_sql`N/A`get_date_dsl`N/ANote that in the "Using `WP_Query` with `'es' => true`" column, "no issues" and "N/A" are not guaranteed. For instance, in almost every filter, the `WP_Query` object is passed by reference. If a plugin or theme modified that object, it could create a conflict. The "no issues" and "N/A" notes assume that filters are being used as intended. Lastly, everything is dependant on `pre_get_posts`. If a plugin or theme were to hook in at a priority &gt; 1000, it could render everything a potential conflict.

Contributing
------------

[](#contributing)

Any help on this plugin is welcome and appreciated!

### Bugs

[](#bugs)

If you find a bug, [check the current issues](https://github.com/alleyinteractive/es-wp-query/issues) and if your bug isn't listed, [file a new one](https://github.com/alleyinteractive/es-wp-query/issues/new). If you'd like to also fix the bug you found, please indicate that in the issue before working on it (just in case we have other plans which might affect that bug, we don't want you to waste any time).

### Feature Requests

[](#feature-requests)

The scope of this plugin is very tight; it should cover as much of WP\_Query as possible, and nothing more. If you think this is missing something within that scope, or you think some part of it can be improved, [we'd love to hear about it](https://github.com/alleyinteractive/es-wp-query/issues/new)!

Unit Tests
----------

[](#unit-tests)

Unit tests are included using phpunit. In order to run the tests, you need to add an adapter for your Elasticsearch implementation.

1. You need to create a file called `es.php` and add it to the `tests/` directory.
2. `es.php` can simply load one of the included adapters which is setup for testing. Otherwise, you'll need to do some additional setup.
3. If you're not using one of the provided adapters:
    - `es.php` needs to contain or include a function named `es_wp_query_index_test_data()`. This function gets called whenever data is added, to give you an opportunity to index it. You should force Elasticsearch to refresh after indexing, to ensure that the data is immediately searchable.
        - **NOTE: Even with refreshing, I've noticed that probably &lt;0.1% of the time, a test may fail for no reason, and I think this is related. If a test sporadically and unexpectedly fails for you, you should re-run it to double-check.**
    - `es.php` must also contain or include a class `ES_WP_Query` which extends `ES_WP_Query_Wrapper`. At a minimum, this class should contain a `protected function query_es( $es_args )` which queries your Elasticsearch server.
    - This file can also contain anything else you need to get everything working properly, e.g. adjustments to the field map.
    - See the included adapters, especially `travis.php`, for examples.

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance49

Moderate activity, may be stable

Popularity38

Limited adoption so far

Community31

Small or concentrated contributor base

Maturity35

Early-stage or recently created project

 Bus Factor1

Top contributor holds 69.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~70 days

Total

3

Last Release

585d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/338d27065b1074f2d66d049d742f22996dd137eef6f91bc8f75350ceee1e8ef2?d=identicon)[srtfisher](/maintainers/srtfisher)

---

Top Contributors

[![mboynes](https://avatars.githubusercontent.com/u/465154?v=4)](https://github.com/mboynes "mboynes (221 commits)")[![mslinnea](https://avatars.githubusercontent.com/u/7308162?v=4)](https://github.com/mslinnea "mslinnea (34 commits)")[![mdbitz](https://avatars.githubusercontent.com/u/5784663?v=4)](https://github.com/mdbitz "mdbitz (9 commits)")[![srtfisher](https://avatars.githubusercontent.com/u/346399?v=4)](https://github.com/srtfisher "srtfisher (8 commits)")[![rebeccahum](https://avatars.githubusercontent.com/u/16962021?v=4)](https://github.com/rebeccahum "rebeccahum (7 commits)")[![chandrapatel](https://avatars.githubusercontent.com/u/9443225?v=4)](https://github.com/chandrapatel "chandrapatel (6 commits)")[![kevinfodness](https://avatars.githubusercontent.com/u/2650828?v=4)](https://github.com/kevinfodness "kevinfodness (5 commits)")[![lipemat](https://avatars.githubusercontent.com/u/1688181?v=4)](https://github.com/lipemat "lipemat (4 commits)")[![jacklenox](https://avatars.githubusercontent.com/u/751476?v=4)](https://github.com/jacklenox "jacklenox (3 commits)")[![kasparsd](https://avatars.githubusercontent.com/u/169055?v=4)](https://github.com/kasparsd "kasparsd (3 commits)")[![nickdaugherty](https://avatars.githubusercontent.com/u/1103700?v=4)](https://github.com/nickdaugherty "nickdaugherty (3 commits)")[![jblz](https://avatars.githubusercontent.com/u/1587282?v=4)](https://github.com/jblz "jblz (2 commits)")[![renatonascalves](https://avatars.githubusercontent.com/u/19148962?v=4)](https://github.com/renatonascalves "renatonascalves (2 commits)")[![xyu](https://avatars.githubusercontent.com/u/373804?v=4)](https://github.com/xyu "xyu (1 commits)")[![david-binda](https://avatars.githubusercontent.com/u/3651036?v=4)](https://github.com/david-binda "david-binda (1 commits)")[![gudmdharalds](https://avatars.githubusercontent.com/u/8835135?v=4)](https://github.com/gudmdharalds "gudmdharalds (1 commits)")[![jameswburke](https://avatars.githubusercontent.com/u/665107?v=4)](https://github.com/jameswburke "jameswburke (1 commits)")[![jesse-greathouse](https://avatars.githubusercontent.com/u/46167019?v=4)](https://github.com/jesse-greathouse "jesse-greathouse (1 commits)")[![kjbenk](https://avatars.githubusercontent.com/u/5174208?v=4)](https://github.com/kjbenk "kjbenk (1 commits)")[![kraftbj](https://avatars.githubusercontent.com/u/88897?v=4)](https://github.com/kraftbj "kraftbj (1 commits)")

### Embed Badge

![Health badge](/badges/alleyinteractive-es-wp-query/health.svg)

```
[![Health](https://phpackages.com/badges/alleyinteractive-es-wp-query/health.svg)](https://phpackages.com/packages/alleyinteractive-es-wp-query)
```

###  Alternatives

[stripe/stripe-php

Stripe PHP Library

4.0k143.3M480](/packages/stripe-stripe-php)[twilio/sdk

A PHP wrapper for Twilio's API

1.6k92.9M272](/packages/twilio-sdk)[facebook/php-business-sdk

PHP SDK for Facebook Business

90821.9M34](/packages/facebook-php-business-sdk)[meilisearch/meilisearch-php

PHP wrapper for the Meilisearch API

74513.7M114](/packages/meilisearch-meilisearch-php)[google/gax

Google API Core for PHP

265103.1M454](/packages/google-gax)[google/common-protos

Google API Common Protos for PHP

173103.7M50](/packages/google-common-protos)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
