PHPackages                             aucor/wp\_query-route-to-rest-api - 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. aucor/wp\_query-route-to-rest-api

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

aucor/wp\_query-route-to-rest-api
=================================

Adds new route /wp-json/wp\_query/args/ to REST API

1.3.2(4y ago)707.8k8[1 issues](https://github.com/aucor/wp_query-route-to-rest-api/issues)GPL-2.0-or-laterPHP

Since Apr 1Pushed 4y ago10 watchersCompare

[ Source](https://github.com/aucor/wp_query-route-to-rest-api)[ Packagist](https://packagist.org/packages/aucor/wp_query-route-to-rest-api)[ Docs](https://github.com/aucor/wp_query-route-to-rest-api)[ RSS](/packages/aucor-wp-query-route-to-rest-api/feed)WikiDiscussions master Synced 1mo ago

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

WP\_Query Route To REST API
===========================

[](#wp_query-route-to-rest-api)

**Contributors:** [Teemu Suoranta](https://github.com/TeemuSuoranta), [Sami Keijonen](https://github.com/samikeijonen), [Christian Nikkanen](https://github.com/k1sul1)

**Tags:** WordPress, REST API, WP\_Query

**License:** GPLv2+

- [Description](#description)
- [How to use](#how-to-use)
    - [Basic usage](#basic-usage)
    - [Use with PHP](#use-with-php)
    - [Use with JS](#use-with-js)
- [Advanced examples](#advanced-examples)
    - [Advanced example: tax\_query](#advanced-example-taxquery)
    - [Advanced example: tax\_query with relation](#advanced-example-taxquery-with-relation)
    - [Advanced example: modifying existing WP\_Query (post archive, term archive, search etc)](#advanced-example-modifying-existing-wpquery-post-archive-term-archive-search-etc)
- [Restrictions](#restrictions)
    - [Allowed args](#allowed-args)
    - [Post types](#post-types)
    - [Post status](#post-status)
    - [Restriction fail-safe](#restriction-fail-safe)
    - [Default WP\_Query](#default-wpquery)
- [Extra plugin compatibility features](#extra-plugin-compatibility-features)
- [Filters](#filters)
- [Hooks](#hooks)
- [Install](#install)
- [Issues and feature whishlist](#issues-and-feature-whishlist)
- [Changelog](#changelog)
    - [1.3.2](#132)
    - [1.3.1](#131)
    - [1.3.0](#130)
    - [1.2.0](#120)
    - [1.1.1](#111)
    - [1.1](#11)

Description
-----------

[](#description)

Adds new route `/wp-json/wp_query/args/` to REST API. You can query content with WP\_Query args. There's extensive filters and actions to limit or extend functionality.

How to use
----------

[](#how-to-use)

### Basic usage

[](#basic-usage)

**Route**: `/wp-json/wp_query/args/`

**Get three projects**: `/wp-json/wp_query/args/?post_type=project&posts_per_page=3`

**You shoudn't write query args by hand!** It gets very complicated when you want to pass arrays for example with meta\_query.

### Use with PHP

[](#use-with-php)

**1. Create $args**

```
$args = array(
  'post_type' => 'post',
  'orderby' => 'title',
  'order' => 'ASC'
);
```

**2. Turn $args into query string** [(Reference)](https://codex.wordpress.org/Function_Reference/build_query)

```
$query_str = build_query( $args );
```

**3. Make the call**

```
$response = wp_remote_get( 'https://your-site.local/wp-json/wp_query/args/?' . $query_str );

// Get array of "post objects"
$posts = json_decode( wp_remote_retrieve_body( $response ) );
```

### Use with JS

[](#use-with-js)

**1. Create args**

```
var args = {
  'post_type': 'post',
  'orderby': 'title',
  'order': 'ASC'
};
```

**2 a) Create params with for example using `@wordpress/url` package**

```
import { addQueryArgs } from '@wordpress/url';

const endpointURL = addQueryArgs( '/wp-json/wp_query/args/', args );
```

**2 b) Some other JS solution**[query-string](https://www.npmjs.com/package/query-string) handles most use cases, but as query strings aren't really standardized, YMMV.

One example of where it falls short:

```
const params = {
  "paged": 1,
  "order": "desc",
  "posts_per_page": 1,
  "tax_query": [
    {
      "taxonomy": "category",
      "field": "term_id",
      "terms": [
        1
      ]
    },
    {
      "taxonomy": "category",
      "field": "term_id",
      "terms": [
        2
      ]
    }
  ]
}
```

One possible solution, ES2015:

```
let qsAdditions = ''

if (params.tax_query) {
  // Define a helper method for getting a querystring part
  const part = (i, key, value) => Array.isArray(value)
    ? value.reduce((acc, v, i2) => (
      acc += `&tax_query[${i}][${key}][${i2}]=${v}`
    ), '')
    : `&tax_query[${i}][${key}]=${value}`

  // Loop the params and glue pieces of querystrings together
  qsAdditions += params_tax_query.reduce((acc, cond, i) => (
    acc += part(i, 'taxonomy', cond.taxonomy || 'category') +
      part(i, 'field', cond.field || 'term_id') +
      part(i, 'terms', cond.terms)
  ), '')

  // Delete value from object so query-string won't parse it
  delete params.tax_query
}

const query_str = querystring.stringify(params) + qsAdditions
```

**2 c) Create params with jQuery**

```
var query_str = jQuery.param( args );
```

**3. Make the call**

```
fetch( addQueryArgs( '/wp-json/wp_query/args/', args ) )
  .then( function ( response ) {
    // The API call was succesful.
    if ( response.ok ) {
      return response.json();
    } else {
      return Promise.reject( response );
    }
  } ).then( function ( data ) {
    // Do something with data.
    console.log( data );
  } ).catch( function ( err ) {
    // There was an error.
    console.warn( 'Something went wrong.', err );
  } );
```

Or with jQuery.

```
$.ajax({
  url: 'https://your.site.local/wp-json/wp_query/args/?' + query_str,
}).done(function( data ) {
  console.log( data );
});
```

Advanced examples
-----------------

[](#advanced-examples)

### Advanced example: tax\_query

[](#advanced-example-tax_query)

Get posts that have **both** tags "wordpress" and "woocommerce"

**PHP:**

```
$args = array(
  'post_type' => 'post',
  'tax_query' => array(
    array(
      'taxonomy' => 'post_tag',
      'field'    => 'slug',
      'terms'    => array( 'wordpress' ),
    ),
    array(
      'taxonomy' => 'post_tag',
      'field'    => 'slug',
      'terms'    => array( 'woocommerce' ),
    ),
  ),
);
```

**JS:**

```
var args = {
  'post_type': 'post',
  'tax_query': [
    {
      'taxonomy': 'post_tag',
      'field': 'slug',
      'terms': [ 'wordpress' ]
    },
    {
      'taxonomy': 'post_tag',
      'field': 'slug',
      'terms': [ 'woocommerce' ]
    }
  ]
};
```

### Advanced example: tax\_query with relation

[](#advanced-example-tax_query-with-relation)

Get posts that have **either** "wordpress" **or** "woocommerce" tag. This gets tricky because JS doesn't support completely the same array structure as PHP. If you only need PHP, this is a piece of cake.

**PHP:**

```
$args = array(
  'post_type' => 'post',
  'tax_query' => array(
    'relation' => 'OR',
    array(
      'taxonomy' => 'post_tag',
      'field'    => 'slug',
      'terms'    => array( 'wordpress' ),
    ),
    array(
      'taxonomy' => 'post_tag',
      'field'    => 'slug',
      'terms'    => array( 'woocommerce' ),
    ),
  ),
);
```

**JS:**

```
var args = {
  'post_type': 'post',
  'tax_query': {
    'relation': 'OR',
    0: {
      'taxonomy': 'post_tag',
      'field': 'slug',
      'terms': [ 'wordpress' ]
    },
    1: {
      'taxonomy': 'post_tag',
      'field': 'slug',
      'terms': [ 'woocommerce' ]
    }
  }
};
```

For other uses, keep in mind JS object/array syntax. If there's key + value, use object `{}`. If theres only value, use array `[]`.

### Advanced example: modifying existing WP\_Query (post archive, term archive, search etc)

[](#advanced-example-modifying-existing-wp_query-post-archive-term-archive-search-etc)

Sometimes you need to create features that add small tweaks to current query that WordPress, theme or plugins has already defined. These include "load more" buttons, filters etc. You can create that query from scratch if you want, but there is a neat way to get the current query for JS.

You can add this to your `archive.php` or whatever PHP template you need:

```

var wp_query = ;
```

Now you can access the query in JS from this var `wp_query`. Props @timiwahalahti for this idea.

Restrictions
------------

[](#restrictions)

The route `/wp-json/wp_query/args/` sets some restrictions by default for queries. These restrictions can be lifted or hardened with filters and actions.

### Allowed args

[](#allowed-args)

```
'p',
'name',
'title',
'page_id',
'pagename',
'post_parent',
'post_parent__in',
'post_parent__not_in',
'post__in',
'post__not_in',
'post_name__in',
'post_type', // With restrictions
'posts_per_page', // With restrictions
'offset',
'paged',
'page',
'ignore_sticky_posts',
'order',
'orderby',
'year',
'monthnum',
'w',
'day',
'hour',
'minute',
'second',
'm',
'date_query',
'inclusive',
'compare',
'column',
'relation',
'post_mime_type',
'author',
'author_name',
'author__in',
'author__not_in',
'meta_key',
'meta_value',
'meta_value_num',
'meta_compare',
'meta_query',
's',
'cat',
'category_name',
'category__and',
'category__in',
'category__not_in',
'tag',
'tag_id',
'tag__and',
'tag__in',
'tag__not_in',
'tag_slug__and',
'tag_slug__in',
'tax_query',
'lang', // Polylang

```

So biggest ones missing have something to do with getting content that you might not want to get like `post_status` drafts (add this argument to the list with filter if you need it). By default, no querying `post_passwords` or having your way with cache settings.

### Post types

[](#post-types)

By default all the post types marked `'show_in_rest' => true` are available. `'post_type' => 'any'` falls back to these post types. You can change post types with filter to what you want.

### Post status

[](#post-status)

By default, only "publish" is allowed. Add other post\_status as needed with filter.

### Restriction fail-safe

[](#restriction-fail-safe)

Addition to restriction of WP\_Query args, there is check after the query that queried posts will not be forbidden post types or post\_status.

### Default WP\_Query

[](#default-wp_query)

```
$default_args = array(
  'post_status'     => 'publish',
  'posts_per_page'  => 10,
  'has_password'    => false
);
```

In addition to the normal defaults from WP\_Query.

Extra plugin compatibility features
-----------------------------------

[](#extra-plugin-compatibility-features)

This plugin has built-in compatibility for [Relevanssi ('s' argument)](https://wordpress.org/plugins/relevanssi/) and [Polylang ('lang' argument)](https://wordpress.org/plugins/polylang/)

Filters
-------

[](#filters)

**Add more allowed args:**

```
function my_allowed_args($args) {
  $args[] = 'post_status';
  return $args;
}
add_filter( 'wp_query_route_to_rest_api_allowed_args', 'my_allowed_args' );
```

**Add more default args:**

```
function my_default_args($args) {
  $args['posts_per_page'] = 5;
  return $args;
}
add_filter( 'wp_query_route_to_rest_api_default_args', 'my_default_args' );
```

**Add allowed post types:**

You can also add post types by setting `'show_in_rest' => true` when registering post type.

```
function my_allowed_post_types($post_types) {
  $post_types[] = 'projects';
  return $post_types;
}
add_filter( 'wp_query_route_to_rest_api_allowed_post_types', 'my_allowed_post_types' );
```

**Add allowed post status:**

```
function my_allowed_post_status($post_status) {
  $post_status[] = 'draft';
  return $post_status;
}
add_filter( 'wp_query_route_to_rest_api_allowed_post_status', 'my_allowed_post_status' );
```

**Is current post allowed:**

```
function my_post_is_allowed($is_allowed, $post) {
  if($post->ID == 123) {
    $is_allowed = false;
  }
  return $is_allowed;
}
add_filter( 'wp_query_route_to_rest_api_post_is_allowed', 'my_post_is_allowed', 10, 2 );
```

**Alter any argument value:**

```
function my_arg_value($value, $key, $args) {
  if($key == 'posts_per_page' && $value > 10) {
    $value = 10;
  }
  return $value;
}
add_filter( 'wp_query_route_to_rest_api_arg_value', 'my_arg_value', 10, 3 );
```

**Check permissions:**

```
function my_permission_check($is_allowed, $request) {
  return true;
}
add_filter( 'wp_query_route_to_rest_api_permissions_check', 'my_permission_check', 10, 2 );
```

**Limit max posts per page:**

```
function my_max_posts_per_page($max) {
  return 100; // Default 50
}
add_filter( 'wp_query_route_to_rest_api_max_posts_per_page', 'my_max_posts_per_page' );
```

**Modify default $data:**

```
function my_default_data($data) {
  $data = array(
    'html'     => false,
    'messages' => array(
      'empty' => esc_html__( 'No results found.', 'text-domain' ),
    ),
  );

  return $data;
}
add_filter( 'wp_query_route_to_rest_api_default_data', 'my_default_data' );
```

**Modify $data after loop:**

```
function my_default_data($data, $wp_query, $args) {
  // Do something with the data.

  return $data;
}
add_filter( 'wp_query_route_to_rest_api_after_loop_data', 'my_default_data', 10, 3 );
```

**Remove post type meta:**

```
add_filter( 'wp_query_route_to_rest_api_update_post_type_meta', '__return_false' );
```

**Remove parent class:**

```
add_filter( 'wp_query_route_to_rest_api_use_parent_class', '__return_false' );
```

Hooks
-----

[](#hooks)

**Before WP\_Query:**

```
function my_before_query($args) {
  // do whatever
}
add_action( 'wp_query_route_to_rest_api_before_query', 'my_before_query' );
```

**After WP\_Query:**

```
function my_after_query($wp_query) {
  // do whatever
}
add_action( 'wp_query_route_to_rest_api_after_query', 'my_after_query' );
```

Install
-------

[](#install)

Download and activate. That's it.

**Composer:**

```
$ composer require aucor/wp_query-route-to-rest-api

```

**With composer.json:**

```
{
  "require": {
    "aucor/wp_query-route-to-rest-api": "*"
  },
  "extra": {
    "installer-paths": {
      "htdocs/wp-content/plugins/{$name}/": ["type:wordpress-plugin"]
    }
  }
}

```

Issues and feature whishlist
----------------------------

[](#issues-and-feature-whishlist)

This is a WordPress plugin by 3rd party developer. WordPress.org or Automattic has nothing to do with this plugin. There's no warranty or quarantees. Thread carefully.

If you see a critical functionality missing, please contribute!

**Looking for similar API to WP\_User\_Query?**

Install also [MEOM/meom-user-query](https://github.com/MEOM/meom-user-query)

Changelog
---------

[](#changelog)

### 1.3.2

[](#132)

Fix PHP warning caused by 1.3.0 argument sanitizing refactoring.

### 1.3.1

[](#131)

Fix composer license to a valid license.

### 1.3.0

[](#130)

Compatibility release with a few new features. 100% backwards compatible.

- Custom HTML output is now allowed (#10)
- Instance and argument sanitizing can be now reused (#11)
- Typos in filter names are fixed while keeping old names also working (#5)
- Updates WP version, plugin version and some readme tweaks

### 1.2.0

[](#120)

WordPress.org release.

### 1.1.1

[](#111)

Added advanced example in readme for getting PHP WP\_Query for JS. Added table of contents. Made the title hierarchy more logical.

### 1.1

[](#11)

Make the return data structure same as /wp-json/wp/posts/. The data schema was missing some data before. Now the structure is inherited from the WP\_REST\_Posts\_Controller as it should have from the start.

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity35

Limited adoption so far

Community19

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor1

Top contributor holds 71.4% 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 ~306 days

Recently: every ~443 days

Total

7

Last Release

1490d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e5cda4dc82223eef9b8360d1d558773856ed36725c8ca2f0d6a6db23cb377133?d=identicon)[Teemu Suoranta](/maintainers/Teemu%20Suoranta)

![](https://www.gravatar.com/avatar/67da7c6634250ac0d91894c83401748dc125034342d2a394a40b0ab5fec92301?d=identicon)[mhgx](/maintainers/mhgx)

---

Top Contributors

[![samikeijonen](https://avatars.githubusercontent.com/u/1820415?v=4)](https://github.com/samikeijonen "samikeijonen (15 commits)")[![TeemuSuoranta](https://avatars.githubusercontent.com/u/9577084?v=4)](https://github.com/TeemuSuoranta "TeemuSuoranta (3 commits)")[![k1sul1](https://avatars.githubusercontent.com/u/2719615?v=4)](https://github.com/k1sul1 "k1sul1 (2 commits)")[![puncle](https://avatars.githubusercontent.com/u/260118544?v=4)](https://github.com/puncle "puncle (1 commits)")

### Embed Badge

![Health badge](/badges/aucor-wp-query-route-to-rest-api/health.svg)

```
[![Health](https://phpackages.com/badges/aucor-wp-query-route-to-rest-api/health.svg)](https://phpackages.com/packages/aucor-wp-query-route-to-rest-api)
```

###  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.9M271](/packages/twilio-sdk)[knplabs/github-api

GitHub API v3 client

2.2k15.8M187](/packages/knplabs-github-api)[facebook/php-business-sdk

PHP SDK for Facebook Business

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

PHP wrapper for the Meilisearch API

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

Google API Core for PHP

263103.1M454](/packages/google-gax)

PHPackages © 2026

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