{"id":18328105,"url":"https://github.com/wpengine/wp-graphql-filter-query","last_synced_at":"2025-04-06T01:32:21.828Z","repository":{"id":79319736,"uuid":"498003086","full_name":"wpengine/wp-graphql-filter-query","owner":"wpengine","description":"Adds taxonomy filtering and aggregation support to WP GraphQL","archived":false,"fork":false,"pushed_at":"2024-11-19T16:45:45.000Z","size":1439,"stargazers_count":17,"open_issues_count":8,"forks_count":2,"subscribers_count":42,"default_branch":"main","last_synced_at":"2025-04-02T20:56:11.943Z","etag":null,"topics":["facets","rd","wordpress","wp-graphql","wp-plugin"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wpengine.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-05-30T15:39:40.000Z","updated_at":"2024-11-19T16:45:47.000Z","dependencies_parsed_at":"2023-12-13T11:37:35.477Z","dependency_job_id":"e6990b69-ac6e-45bc-b7c5-38ca6cd05db6","html_url":"https://github.com/wpengine/wp-graphql-filter-query","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wpengine%2Fwp-graphql-filter-query","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wpengine%2Fwp-graphql-filter-query/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wpengine%2Fwp-graphql-filter-query/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wpengine%2Fwp-graphql-filter-query/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wpengine","download_url":"https://codeload.github.com/wpengine/wp-graphql-filter-query/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247423477,"owners_count":20936621,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["facets","rd","wordpress","wp-graphql","wp-plugin"],"created_at":"2024-11-05T19:13:09.541Z","updated_at":"2025-04-06T01:32:16.846Z","avatar_url":"https://github.com/wpengine.png","language":"PHP","readme":"# WPGraphQL Filter Query\n\nAdds taxonomy filtering and aggregation support to [WPGraphQL](https://www.wpgraphql.com).\n\n- [WPGraphQL Filter Query](#wpgraphql-filter-query)\n  - [WPGraphQL limitation](#wpgraphql-limitation)\n    - [Solution](#solution)\n  - [What are Filters (and Aggregates)](#what-are-filters-and-aggregates)\n    - [Use Case Example](#use-case-example)\n  - [Querying with Filters](#querying-with-filters)\n  - [Advanced Queries](#advanced-queries)\n    - [Multiple Comparison Operators on one Taxonomy](#multiple-comparison-operators-on-one-taxonomy)\n    - [Multiple Relation Operators on Multiple Taxonomies](#multiple-relation-operators-on-multiple-taxonomies)\n    - [Nesting Relation Operators on Multiple Taxonomies](#nesting-relation-operators-on-multiple-taxonomies)\n  - [Readable Filter Queries](#readable-filter-queries)\n  - [Dependencies](#dependencies)\n  - [Install and Activate](#install-and-activate)\n  - [Contributing](#contributing)\n    - [Requirements](#requirements)\n    - [Getting Started](#getting-started)\n    - [Testing](#testing)\n    - [Linting](#linting)\n    - [VSCode](#vscode)\n\n## WPGraphQL limitation\n\nThe introduction of WPGraphQL helped make access to WordPress headless data even easier than via REST, but there are still some areas and use-cases that are outside that repository’s existing focus or scope. From interfacing with the WPGraphQL team it was noted that there was a community desire for a query filter argument implementation to extend the existing plugin, which could support scenarios such as the **taxQuery** candidate [here](https://github.com/wp-graphql/wp-graphql/pull/1387).\n\n### Solution\n\nIn collaboration with the WPGraphQL team we built this plugin to:\n\n-   Add a `filter` WPGraphQL input argument connection, for all Post types, which supports the passing of multiple Taxonomies for refinement.\n-   Add an `aggregation` field connection, available in the body of all Post types, which can return a sum of the names of each Taxonomy that occurs, and a count of the number of occurrences of each, in each query response.\n\n## What are Filters (and Aggregates)\n\nFilters allow the limiting of Post results by **Taxonomy** fields \u0026 values. Aggregates give a summary of such Taxonomies available to a given query - based on a sum of the resulting Posts associated Taxonomies. So, if one queried all Posts on _food_ (this would need to be the name of a related Taxonomy here) from a Lifestyle blog, one might expect to receive all food-related Posts, plus the sum of all Taxonomies that occurred within the Posts' results - such as _sweet_ or _savory_, but probably not _home decor_ or _yoga_ (unless a topic related to both _food_ and _yoga_ perhaps).\n\nBroadly speaking, WordPress Taxonomies have two default types: **Categories \u0026 Tags**. **Categories** are more of a grouping mechanism, which supports hierarchy and siblings (_animal-\u003e feline-\u003e tiger, lion, cat_), whereas **Tags** are more for additional shared information (_green, heavy, out-of-stock_). This plugin supports both of these Taxomonies within both Filters and Aggregates.\n\n### Use Case Example\n\nUsing an example of a fictional _Sample Clothing Store_ WordPress site we can further illustrate the use of filters. Here, the products are separated into 4, sometimes overlapping, Categories: _Sport_, _Formal_, _Footwear_ and _Accessories_ - there will be no inheritance Categories in this simple example, but some sibling Categories. There are 6 possible Tags also available, for further information on and grouping of the stock, and for shared traits: _Keep Warm_, _Keep Cool_, _Waterproof_, _On Sale_, _Cushioning_, and _Gym_. The 12 products are shown in the image below - 4 in each Category, but one can see _Leather Shoes_ shares both Formal and Footwear Categories, while _Gym Trainers_ shares both Sport and Footwear Categories. The blue numbers below each product show their associated Tags.\n\n![Simple Clothing Store](docs/img/simple-clothing-store.png)\n\nNow, if we pictured this sample store having its own website frontend (reading from our WordPress Headless WPGraphQL) which could display all of the products, and allow filtering by the Categories and Tags e.g. **query #1** image.\n\nIn this query the customer has visited perhaps a _Featured Sportswear \u0026 Footwear_ section, from one of the website’s homepage links, which automatically filter-queried the products by the given Categories of _Sport \u0026 Footwear_, while also returning the Aggregations of still-applicable Taxonomies (by name \u0026 occurrence count).\n\nFrom this filter-by-category view the customer could then further refine what products they are interested in, by selecting only certain Tags from the Aggregated Tags returned (which was all 6 in this example). Next, in the **query #1** image below, one can see some of the Tag boxes being checked so that, by **query #2**, we can see the products returned from the filter-by-category-and-tag query have gone from 6 (Gym T-shirt, Hoodie, Sweat Pants, Leather Shoes, Sandals, Gym Trainers) to 4 (Gym T-shirt, Sweat Pants, Sandals, Gym Trainers) in number.\n\nWe can see in both query results that:\n\n-   Of the 6 Products returned in **query #1**, there were occurrences of all 6 Tags with a sum of 15 instances (again, the aggregate/ sum of Tags, by name \u0026 counts).\n-   By **query #2**, even though we specified 2 tags to filter by, the 4 Products returned contained a total of 4 associated Tags (each had both specified \u0026 unspecified Tags) and 12 instances.\n\n![Filtered Simple Clothing](docs/img/filtered-simple-clothing.png)\n\nThis above example uses, by default, an `and` relationship between the specified Taxonomies, but this plugin supports both `AND` plus `OR` relationships within its filters - these are the **relation** operators. In this example a multiple-equality ‘in’ ‘comparison’ operator is used as the comparison for filtering, but this plugin supports all of the following comparison operators: `eq`, `notEq`, `like`, `notLike`, `in`, `notIn`.\n\n## Querying with Filters\n\nGiven the **Simple Clothing Store** website above, we can start seeing how one would go about benefiting from filter queries in **query #1 and #2**. To replicate the backend needed to supply such frontend functionality we must first create a WP instance with **WPGraphQL** \u0026 our **WPGraphQL Filter Query** plugins installed and activated. Then we need to clear any default data and add the 4 Categories, 6 Tags, and 12 Products (as Posts) from our earlier data, and establish the specified relationships between our Products, Tags and Categories. Once this is done one can begin querying the data via WPGraphQL’s inbuilt GraphiQL IDE (a familiarity with this is assumed).\n\nThe **query #1** should look roughly like this, with Filter by Category:\n\n```graphql\nquery Query1 {\n  posts(filter: { category: { name: { in: [\"Sport\", \"Footwear\"] } } }) {\n    nodes {\n      title\n    }\n\n    aggregations {\n      tags {\n        key\n        count\n      }\n\n      categories {\n        key\n        count\n      }\n    }\n  }\n}\n```\n\n![Query #1](docs/img/query-1.png)\n\n**Query #2** builds on 1, with the addition of selected (UI-checked) Tags to Filter.\n\nWhen we add Tags to the filter an implicit Relation Operator of `and` is applied between the Category and the Tag objects - _if (Category-match \u0026\u0026 Tag-match) return Post(s)_.\n\n```graphql\nquery Query2 {\n  posts(\n    filter: {\n      category: { name: { in: [\"Sport\", \"Footwear\"] } }\n      tag: { name: { in: [\"On Sale\", \"Gym\"] } }\n    }\n  ) {\n    nodes {\n      title\n    }\n\n    aggregations {\n      tags {\n        key\n        count\n      }\n\n      categories {\n        key\n        count\n      }\n    }\n  }\n}\n```\n\n![Query #2](docs/img/query-2.png)\n\n## Advanced Queries\n\n### Multiple Comparison Operators on one Taxonomy\n\nIf the **query #2** was taken a step further to perhaps exclude the _Gym Tag_, we could see only _Sandals_ would make a return as _On Sale_. This is the lowest level of chaining operators, and the relation operator for these will always be `and`. We also see a new Comparison Operator, coupled with the previous one: `notEq`:\n\n```graphql\nquery ProductsByFilterNotEqGym {\n  posts(\n    filter: {\n      category: { name: { in: [\"Sport\", \"Footwear\"] } }\n      tag: { name: { in: [\"On Sale\", \"Gym\"], notEq: \"Gym\" } }\n    }\n  ) {\n    nodes {\n      title\n    }\n\n    aggregations {\n      tags {\n        key\n        count\n      }\n\n      categories {\n        key\n        count\n      }\n    }\n  }\n}\n```\n\n![Results of notEq example](docs/img/sandals-results.png)\n\n### Multiple Relation Operators on Multiple Taxonomies\n\nThis plugin supports 4 root filter query arguments presently:\n\n-   2 Taxonomies: ‘Tag’ \u0026 ‘Category’ (Covered already)\n-   2 Relation Operators: `or` \u0026 `and`\n    -   These cannot appear as siblings, so use one or neither, per nested object\n    -   These accept an array of root filter query objects (so, each object of array itself can have Taxonomies, or/and Relation Operators, recursively)\n    -   Nested filter query objects can be nested up to 10 times presently\n\nGiven **query #2** as a starting point, we could separate the two Tags to be searched into their own filter query object, inside an `or` Relation Operator and get the same result (Also switched the Comparison Operator here to `eq`, vs `in` as there was only one Tag comparison made in each object now):\n\n```graphql\nquery ProductsByFilterOROperator {\n  posts(\n    filter: {\n      category: { name: { in: [\"Sport\", \"Footwear\"] } }\n      or: [\n        { tag: { name: { eq: \"On Sale\" } } }\n        { tag: { name: { eq: \"Gym\" } } }\n      ]\n    }\n  ) {\n    nodes {\n      title\n    }\n\n    aggregations {\n      tags {\n        key\n        count\n      }\n\n      categories {\n        key\n        count\n      }\n    }\n  }\n}\n```\n\n![Results of OR example](docs/img/results-of-query-or-example.png)\n\n### Nesting Relation Operators on Multiple Taxonomies\n\nIf we simply swap the Relation Operator to `and` now on this previous query our results now must contain both Tag Comparison Operator matches, rather than either or. This eliminates _Sandals_, which only had the _On Sale_ Tag, but not the _Gym_ one.\n\n```graphql\nquery ProductsByFilterANDOperator {\n  posts(\n    filter: {\n      category: { name: { in: [\"Sport\", \"Footwear\"] } }\n      and: [\n        { tag: { name: { eq: \"On Sale\" } } }\n        { tag: { name: { eq: \"Gym\" } } }\n      ]\n    }\n  ) {\n    nodes {\n      title\n    }\n\n    aggregations {\n      tags {\n        key\n        count\n      }\n\n      categories {\n        key\n        count\n      }\n    }\n  }\n}\n```\n\n![Results of OR example](docs/img/results-of-query-or-example.png)\n\n## Readable Filter Queries\n\nUsing the relation operators are powerful, and were made to be siblings of Taxonomies, but, for greatest clarity do not reply on the implicit `and` relation of siblings at filter query level. As mentioned, nesting of queries is available via relation operators, up to a depth of 10, but this may be somewhat unreadable, like nested callbacks.\n\n## Dependencies\n\nIn order to use WPGraphQL Filter Query, you must have [WPGraphQL](https://www.wpgraphql.com) installed and activated.\n\n## Install and Activate\n\nWPGraphQL Filter Query is not currently available on the WordPress.org repository, so you must [download it from Github](https://github.com/wpengine/wp-graphql-filter-query/archive/refs/heads/main.zip).\n\n[Learn more](https://wordpress.org/support/article/managing-plugins/) about installing WordPress plugins from a Zip file.\n\n## Contributing\n\n### Requirements\n\n-   Docker\n\n### Getting Started\n\nTo get started with the dev environment run\n\n```\nmake\n```\n\n### Testing\n\n```\nmake test\n```\n\n### Linting\n\n```\nmake lint\n```\n\n### VSCode\n\nInstall the following plugins to gain formatting and lint errors showing up in the editor\n\n![image](https://user-images.githubusercontent.com/24898309/174314127-6238f618-0355-4187-b43c-c7a81f451c5f.png)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwpengine%2Fwp-graphql-filter-query","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwpengine%2Fwp-graphql-filter-query","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwpengine%2Fwp-graphql-filter-query/lists"}