PHPackages                             sanderdekroon/parlant - 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. sanderdekroon/parlant

ActiveLibrary

sanderdekroon/parlant
=====================

An expressive way to query posts in WordPress.

0.1.0(7y ago)06MITPHPPHP ~5.6|~7.0

Since Jan 31Pushed 7y ago1 watchersCompare

[ Source](https://github.com/sanderdekroon/parlant)[ Packagist](https://packagist.org/packages/sanderdekroon/parlant)[ Docs](https://github.com/sanderdekroon/parlant)[ RSS](/packages/sanderdekroon-parlant/feed)WikiDiscussions master Synced yesterday

READMEChangelogDependencies (2)Versions (5)Used By (0)

Parlant
=======

[](#parlant)

[![Latest Version on Packagist](https://camo.githubusercontent.com/d96e35fd0a63c51992c24338e7370e09fa2e3e82dd8c02823c8b179f2fcc9700/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f73616e64657264656b726f6f6e2f7061726c616e742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/sanderdekroon/parlant)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)[![Build Status](https://camo.githubusercontent.com/feed5074f86d01794a07be0acea9022fbc5a03d4bbc68c007219190e71dffa81/68747470733a2f2f696d672e736869656c64732e696f2f7472617669732f73616e64657264656b726f6f6e2f7061726c616e742f6d61737465722e7376673f7374796c653d666c61742d737175617265)](https://travis-ci.org/sanderdekroon/parlant)[![Coverage Status](https://camo.githubusercontent.com/30227b836140d4a3ddd268b03086c71d20fbe80d725a709a55cb9e09916b94c9/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f73616e64657264656b726f6f6e2f7061726c616e742f6261646765732f636f7665726167652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/sanderdekroon/parlant/?branch=master)[![Quality Score](https://camo.githubusercontent.com/cd52454041c6395db07c251144012db5fd7ae271707f634cf5d6c746624c8cf7/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f672f73616e64657264656b726f6f6e2f7061726c616e742e7376673f7374796c653d666c61742d737175617265)](https://scrutinizer-ci.com/g/sanderdekroon/parlant)[![Total Downloads](https://camo.githubusercontent.com/13ef5fef8dfc13a567b866aa96066ada05b2d6ba2f28dd00f8b9d11d321db2c3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f73616e64657264656b726f6f6e2f7061726c616e742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/sanderdekroon/parlant)

Parlant is a PHP library to query posts within WordPress in an expressive way. Get rid of the messy WP\_Query array's and start writing expressive queries.

Remember this?

```
$args = array(
  'post_status' => 'future',
  'meta_query' => array(
     array(
        'key' => '_thumbnail_id',
        'value' => '',
        'compare' => '!='
     )
  )
);
$slider_posts = new WP_Query($args);
```

What if you could simplify it to this?

```
$slider_posts = Post::type('post')
    ->where('post_status', 'future')
    ->whereMeta('_thumbnail_id', '!=', '')
    ->get();
```

Parlant is a Query Builder, which means you can build queries in a simple and expressive way. It still uses WP\_Query under the hood, but it takes away the pain and clutter of argument building.

Install
-------

[](#install)

Via Composer

```
$ composer require sanderdekroon/parlant
```

Usage
-----

[](#usage)

### Basic usage

[](#basic-usage)

Parlant's syntax is heavily inspired by [Laravel's Query Builder](https://github.com/illuminate/database) package.

To start building queries, simply start by calling the static method `type()` on the Parlant class. Either pass in the posttype you're querying into the `type()` method or call `all()` to query all posttypes.

These methods return a `PosttypeBuilder` instance on which you can chain multiple methods. End a query by calling `get()` to get all results of the query.

Although Parlant uses `WP_Query` in the background, it overrides some of it's default settings. Parlant will, by default, return all found posts (`'posts_per_page' => -1`) instead of the default. This behavior can be overwritten by changing the settings of Parlant.

For example: get all posts of posttype 'article':

```
use Sanderdekroon\Parlant\Posttype as Post;

$articles = Post::type('article')->get();
```

The variable `$articles` will now contain an array of WP\_Post instances. Alternatively Parlant can be configured to return a WP\_Query instance or an array of query arguments. It is also possible to inject your own output formatter.

### Limiting results

[](#limiting-results)

Besides changing Parlant's configuration, it's also possible to pass any limiting methods to the Query Builder. Instead of calling `get()` to return results, you can call `first()` to return the first result:

```
$article = Post::type('article')->first();
```

Depending on your configuration, this returns a single WP\_Post instance. Remember, you can define your own output settings.

When you're needing a specific amount of posts to be returned, add the `limit()` method to the query and end it with `get()`:

```
$fiveArticles = Post::type('article')->limit(5)->get();
```

### Specify results

[](#specify-results)

Use the `where()` method when specifying results. Basically, all the arguments used for WP\_Query in the outer array are supported through this method.

For example, you can specify the author by calling `where('author', 7)` on the PosttypeBuilder. Want to get all posts in 1970? Go right ahead: `where('year', 1970)`.

A simple query with `where()` would look like this:

```
use Sanderdekroon\Parlant\Posttype as Post;

// Get all articles that are within the category called 'linux',
// limited to 5 results.
Post::type('articles')
    ->where('category_name', 'linux')
    ->limit(5)
    ->get();
```

It's possible to add multiple where statements, apply a limiting method and order the result. All in one chain.

```
// Get articles written by author 42, within the category called 'Meaning of Life'
// and limit it to 14 results.
Post::type('articles')
    ->where('author', '42')
    ->where('category_name', 'Meaning of Life')
    ->orderBy('title', 'ASC')
    ->limit(14)
    ->get();
```

### Meta query

[](#meta-query)

Of course you can also utilize the meta\_query of the WP\_Query class. Just add the `whereMeta()` method. This means you will be querying for certain post\_meta key/value combination. For example:

```
// Get all posts within the posttype 'post' where the post_meta key 'foo' should be equal to 'bar'.
Post::type('post')->whereMeta('foo', '=', 'bar')->get();
```

#### Operators

[](#operators)

You can pass in any of the supported operators. If no operator is supplied, Parlant defaults to '='.

```
// Get all posts within the 'post' posttype where the post_meta key 'secretkey' is not equal to 'hunter2'.
Post::type('post')->whereMeta('secretkey', '!=', 'hunter2')->get();
```

Since Parlant is utilizing the WP\_Query class, you can pass in any of the supported operators of WP\_Query. For reference, the operators are:

```
=, !=, >, >=,  **Note:** Just like with a normal `whereMeta()` method, you can still pass in different operators and meta types.

#### Nesting madness

[](#nesting-madness)

Parlant will resolve all nested queries recursively, so there's no hard limit on the level of queries.

```
Post::type('*')->whereMeta(function() {
        return $this->relation('OR')
            ->where('size', 'L')
            ->where('size', 'M')
            ->where(function() {
                return $this->relation('AND')
                    ->where('color', 'RED')
                    ->where('fit', 'slim')
                    ->where(function() {
                        return $this->where('foo', 'bar')
                        ->where('bar', 'baz');
                    });
            });
    })->get()
```

Although it's possible to nest the queries quite deep, I would not recommend to go deeper than 3 levels.

*Just for your own sanity.*

### Taxonomy queries / Term queries

[](#taxonomy-queries--term-queries)

Besides custom post meta, it's also possible to query custom taxonomies. Like the meta query, start a taxonomy/term query by using the `whereTerm()` method. Start by passing in the taxonomy, then the term field, the operator (optional) and finally the term value.

```
// Get all posts within the posttype 'jeans' that are within the term called '37' of the 'size' taxonomy.
Post::type('jeans')->whereTerm('size', 'name', 'IN', 37)->get();
```

Of course you can pass in any of the other tax query operators. Omitting the operator will make Parlant fallback to the default 'IN' operator.

> **Note:** the tax query has different operators than the meta query. The operators are IN, NOT IN, AND, EXISTS, NOT EXISTS.

#### Taxonomy/Term relation

[](#taxonomyterm-relation)

The relationship handling between multiple taxonomy queries is handled the same way as a meta query. Chaining multiple `whereTerm()` methods will create an 'AND' relation by default. Use `orWhereTerm()` to set the relation to 'OR'.

For example: we want to query all posts within the posttype 'jeans' but only want the posts where the size is either '32' or '33'. In this example, size is the taxonomy.

```
Post::type('jeans')
    ->whereTerm('size', 'name', '32')
    ->orWhereTerm('size', 'name', '33')
    ->get();
```

The taxonomy/term query also supports nested queries. There's one difference: there's no need to specify which field you are querying as there are different methods taking care of that. When you're within a closure constructing a nested query, simply call the field you want to query as a method. E.g. `slug()`, `name()`, `id()` or `termTaxonomyId()`.

Continuing from the example above, we want to get all jeans where the size is either '32' or '33' and where the color is 'blue'.

```
Post::type('jeans')
    ->whereTerm(function() {
        return $this->relation('OR')
            ->name('size', '32')
            ->name('size', '33');
    })
    ->whereTerm('color', 'term_slug', 'blue')
    ->get();
```

It's possible to mix the different methods when you are within a nested taxonomy query.

#### Setting a default taxonomy

[](#setting-a-default-taxonomy)

When you are querying a lot of values within a single taxonomy, it's possible to set a default taxonomy for a nested taxonomy query. Instead of immediately starting a closure, pass in the taxonomy name first and then a closure:

```
// Query all jeans that are either in the term 32, 33, 34 or 35, within the 'size' taxonomy.
Post::type('jeans')
    ->whereTaxonomy('size', function () {
        return $this->relation('OR')->name('32')->name('33')->name('34')->name('35');
    })->get();
```

Configuration
-------------

[](#configuration)

The default configuration of Parlant can be changed at any time, but it's recommended to configure it as early as possible to avoid unexpected results. Changes are made by calling the `configure()` method on an instance of Parlant.

These settings are set globally, so there's no need to change the configuration every time you're starting a query. Parlant configures itself to return all posts which are published and returns found posts as an array of `WP_POST` instances.

```
use Sanderdekroon\Parlant\Configurator\ParlantConfigurator;

ParlantConfigurator::globally([
    'posts_per_page'    => -1,
    'post_type'         => 'any',
    'post_status'       => 'publish',
    'return'            => 'array',
]);
```

> **Note:** This is the default configuration, there's no need to copy this exact code. Use it as a reference or starting point.

Now let's change the default posts\_per\_page from -1 to 9.

```
use Sanderdekroon\Parlant\Configurator\ParlantConfigurator;

ParlantConfigurator::globally(['posts_per_page' => 9]);
```

### Changing output

[](#changing-output)

Parlant uses Output Formatters to determine how to output the query results. By default it will return an array of WP\_Post instances. If you want to start a `WP_Query` loop, simply change the default settings of Parlant:

```
use Sanderdekroon\Parlant\Configurator\ParlantConfigurator;

ParlantConfigurator::globally(['return' => 'query']);
```

This configuration will make Parlant return a WP\_Query instance on all queries. If you only want to change the ouput of one query, call the `setConfig()` method on a `PosttypeBuilder `instance:

```
use Sanderdekroon\Parlant\Posttype as Post;

Post::any()->setConfig('return', 'query')->get();
```

Parlant has three built in output formatters:

- `array`, which will output an array of WP\_Post instances
- `argument`, which will output the raw query arguments
- `query`, which will output a WP\_Query instance

Alternatively, you can supply your own output formatter by supplying the fully namespaced classname. The formatter should adhere to the `Sanderdekroon\Parlant\Formatter\FormatterInterface` interface which looks like this:

```
namespace Sanderdekroon\Parlant\Formatter;

interface FormatterInterface
{

    public function output(array $queryArguments);
}
```

The `output()` method always receives an array of arguments. As an example, the query formatter looks like this:

```
namespace Sanderdekroon\Parlant\Formatter;

use WP_Query;

class QueryFormatter implements FormatterInterface
{
    /**
     * Return an instance of WP_Query
     * @param  array  $arguments
     * @return WP_Query
     */
    public function output(array $arguments)
    {
        $query = new WP_Query($arguments);

        return $query;
    }
}
```

Methods
-------

[](#methods)

Below is a list of supported methods and their parameters. Some methods have not yet been implemented, but will be added in future versions.

### Returns results

[](#returns-results)

`get()` - Returns all results

`first()` - Returns only the first result.

`all()` - Same as get, but ignores the `limit()` method or any other default setting.

`count()` - Returns an integer representing the count of found posts.

`find($id)` - Returns a single result (if any) where the ID is equal to the integer passed in.

`pluck($column_name)` - Only returns an array of the specified column name.

`avg('column_name')` - Will trigger a BadMethodCallException as this is unimplemented.

`max('column_name')` - Will trigger a BadMethodCallException as this is unimplemented.

`min('column_name')` - Will trigger a BadMethodCallException as this is unimplemented.

### Limiting methods

[](#limiting-methods)

`limit($number)` - Limits the output to the number passed in.

`select('column_name')` - Will trigger a BadMethodCallException as this is unimplemented.

### Where

[](#where)

`where($column, $value)` - Specifies the result.

`whereMeta()` - Specify the result by searching for a certain meta key/value relation.

`whereTaxonomy()` - Specify the result by searching for a certain taxonomy/term relation.

`whereBetween() / whereNotBetween()` - Will trigger a BadMethodCallException as this is unimplemented.

`whereIn() / whereNotIn()` - Will trigger a BadMethodCallException as this is unimplemented.

### Ordering

[](#ordering)

`orderBy($column, $direction = null)` - Order the result by a given column. The direction parameter is optional.

`order($direction)` - Specify in which direction the results should be ordered. Usually this is not needed, as the `orderBy()` method can be used to specify the direction.

`groupBy()` - Will trigger a BadMethodCallException as this is unimplemented.

`inRandomOrder()` - Will trigger a BadMethodCallException as this is unimplemented.

Change log
----------

[](#change-log)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Testing
-------

[](#testing)

```
$ composer test
```

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

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

23

—

LowBetter than 27% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity4

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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

Unknown

Total

1

Last Release

2749d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/94b4d2ed317ac574b0058eca1b6231fa47aaaf5b88692798c08a1553d4be7a39?d=identicon)[sanderdekroon](/maintainers/sanderdekroon)

---

Top Contributors

[![sanderdekroon](https://avatars.githubusercontent.com/u/1830845?v=4)](https://github.com/sanderdekroon "sanderdekroon (81 commits)")

---

Tags

wordpressquerybuilderpostssanderdekroonparlant

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/sanderdekroon-parlant/health.svg)

```
[![Health](https://phpackages.com/badges/sanderdekroon-parlant/health.svg)](https://phpackages.com/packages/sanderdekroon-parlant)
```

###  Alternatives

[wp-cli/wp-cli

WP-CLI framework

5.0k17.2M320](/packages/wp-cli-wp-cli)[wp-coding-standards/wpcs

PHP\_CodeSniffer rules (sniffs) to enforce WordPress coding conventions

2.7k42.5M1.6k](/packages/wp-coding-standards-wpcs)[composer/installers

A multi-framework Composer library installer

1.4k136.0M6.0k](/packages/composer-installers)[phpcompatibility/phpcompatibility-wp

A ruleset for PHP\_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.

21830.6M587](/packages/phpcompatibility-phpcompatibility-wp)[szepeviktor/phpstan-wordpress

WordPress extensions for PHPStan

3257.8M898](/packages/szepeviktor-phpstan-wordpress)[php-stubs/wordpress-stubs

WordPress function and class declaration stubs for static analysis.

19013.0M263](/packages/php-stubs-wordpress-stubs)

PHPackages © 2026

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