We should be able to fetch a single term by it's slug, possibly other attributes?
Similar to how we can now get post objects by URI, ID and Global ID.
We should also think about what other objects we should be able to get by something other than ID. I think Users would probably be another good candidate. The way I'm thinking about it, is anything that would have it's own route in an SPA should be able to be retrieved by slug.
@CodeProKid agreed. Which also makes me think the singular queries for nodes just need to be more flexible. Right now we have post( id: "someId" ) or postBy() which has the following args: id, postId, slug, uri. . .
Ideally, I'd like one singular entry point per node, instead of post(), and postBy(), especially if we're going to add it for each type of node. . .might be best to make a breaking change and make the existing singular entries more flexible where id is not a required input $arg.
I think it would be good to instead support a single where field, similar to how we do connections, and can nest other inputs on it. . .like:
query getNodes ( $postWhere: postWhere!, $userWhere: userWhere ) {
post( where: $postWhere ) {
id
title
}
user ( where: $userWhere ) {
id
firstName
lastName
}
}
$variables = {
'postWhere': {
id: null,
slug: "some-post",
uri: null,
postId: null
},
'userWhere': {
id: null,
username: null,
email: "[email protected]"
}
};
This shape brings some consistency to the shape of the args for singular nodes and connections now, and it gives more flexibility to using variables individually or in combination to narrow the resulting node, and more flexibility to plugins to extend the shape with their own fields.
I imagine all sorts of ways folks would want to get a users (or other nodes) by some unique value, like user(where: {wooCommerceOrderNumber: 123} ) or something to that tune.
Changing the shape of the root singular entries will be a breaking change, but I think now is the time to do it.
Also, the postBy() field only makes semantic sense if there are no additional fields in the schema. . .for example, posts _can_ have passwords, so we will need to add a password input arg, and postBy( password: "123", slug: "some-slug") isn't as nice (to me) as post( where: { slug: "some-slug" }, password: "123456" )
Definitely looking forward to this one! I agree that it feels like a good time to introduce this breaking change ahead of 1.0.
Hi, I wonder if you're still working on this feature?
I'm implementing a SPA of my Wordpress website using WPGraphQL and React. When I go to the blog page I'm trying to filter posts by categories. So I can have the same functionality as in Wordpress.
I haven't found an equivalent to postBy (I thought it would be something like categoryBy), so I ended up using the category ID field to filter posts, which works ok but it makes the URL not so friendly :)
This is what I'm currently doing:
/blog/category/mobile?id=Y2F0ZWdvcnk6Mw%3D%3D
This is what I'd like to have.
/blog/category/mobile
This is my current query:
query GetPostsByCategory($categoryId: ID!) {
category(id: $categoryId) {
id
name
link
slug
posts {
edges {
node {
id
title
date
excerpt
slug
author {
name
}
featuredImage {
sourceUrl
}
}
}
}
}
}
Is there any alternative to do this? Or should I wait until this issue is resolved?
@matiasalvarez87 I do plan on working on this at some point, but I don't have an ETA right now.
For what you're trying to do, you could do this:
query GetCategoryPosts($first: Int, $where: RootCategoriesTermArgs!) {
categories(first: $first, where: $where) {
edges {
node {
id
name
slug
count
posts {
edges {
node {
id
title
}
}
}
}
}
}
}
and variables
{
"first": 1,
"where": {
"slug": "alignment"
}
}
You can actually test this over at https://playground.wpgraphql.com 馃槃
So now you can get the slug from the route, and use that in your variables.
This is probably better than getting a single node anyway via category { ... } as the edge data will likely come in handy at some point. . .for example, providing next/prev links. . .that's edge data based on the context of the list you're paginating through
Hi @jasonbahl! I was not aware of the WPGraphQL playground, it looks really nice!
The query you sent works. Thanks for your comments.
@jasonbahl I was having a similar issue, and I am using a query close to what you suggested. Which worked perfectly. However, I am not getting any results when I query with a slug that is a child of another term. Any ideas on what I could be missing?
@CorneliusIV can you provide the exact query you're trying (along with variables, if any) and provide some info on the term hierarchy so I can try and replicate the scenario and see what I can find.
@jasonbahl Sure
I have custom Taxonomy called Regions
Under Regions, I have a parent term North America and a child Canada
So:
North America
-- Canada
Using a query very similar to what you suggested
query GetRegionsSlug($first: Int, $where: RootRegionsTermArgs!) {
regions(first: $first, where: $where) {
edges {
node {
id
name
slug
count
posts {
edges {
node {
id
title
date
content
}
}
}
}
}
}
}
Variable
{
"first": 1,
"where": {
"slug": "canada"
}
}
Result:
{
"data": {
"regions": {
"edges": []
}
}
}
If I try to search for North America
Variable
{
"first": 1,
"where": {
"slug": "north-america"
}
}
I get somewhat of an expected result, but posts returns a post that is tagged with Canada
{
"data": {
"regions": {
"edges": [
{
"node": {
"id": "cmVnaW9uczo1NQ==",
"name": "North America",
"slug": "north-america",
"count": null,
"posts": {
"edges": [
{
"node": {
"id": "cG9zdDo2NzY=",
"title": "Test Post",
"date": "2018-06-27 15:07:16",
"content": ""
}
}
]
}
}
}
]
}
}
}
@CorneliusIV thanks for the info!
So, Test Post is tagged with Canada but _not_ tagged with North America?
@jasonbahl correct
@jasonbahl this seems like something that should happen relatively soon. I know we have talked about changing the shape of the single object queries pretty radically.
Also, fwiw I think the args for getting a single object should be limited to those that are considered "unique" for the object. I know that technically a lot of them aren't, but querying by something like slug (aka guid) seems legit to me.
I think there will also have to be some performance considerations when implementing this. I'm not crazy about doing some of these queries with WP_Query and the like, but I'm not sure that there is a better option.
I think being able to get nodes by permalink/URL would be a really useful feature. For example I'm looking at pulling MediaItem nodes based on URL's found in post content or other html, but I'm not sure I can reliably use the URL to get the URI to make the query.
Sorry, just realized I actually mean querying MediaItem nodes by sourceUrl which is a totally different thing than what I wrote
The next release I'm working on (#1086) addresses this (the ability to fetch single nodes by various forms of unique identifiers).
We're deprecating the $postType.'By' entry points, and have added a new idType field and enum for single entry points.
This means queries such as the following will still work, but will not show in the Schema documentation, and may be formally removed from the codebase at a later date:
{
postBy( slug: "some-slug" ) {
id
title
}
}
{
pageBy( uri: "some-uri" ) {
id
title
}
}
md5-c6d4746a011ba27ae782804b11738c62
{
post(id: 1739, idType: DATABASE_ID) {
id
title
uri
slug
postId
}
}
md5-bc831581545daf991e54f021294b1bed
{
post(id: "/test-5/", idType: URI) {
id
title
uri
slug
postId
}
}
md5-0dcf7135f497d8bab000d14bbdc47a69
{
post(id: "cG9zdDoxNzM5", idType: ID) {
id
title
uri
slug
postId
}
}
md5-7210c2f1c6c778c9666401ca718781cb
{
post(id: "cG9zdDoxNzM5") {
id
title
uri
slug
}
}
md5-000f991f2ddaa95210d1b7c84564c017
{
post(id: "test-5", idType: SLUG) {
id
title
uri
slug
}
}
md5-b11a4b739ba7ee55e94ef32b4244f508
{
contentNodes {
nodes {
__typename
id
title
link
uri
isRevision
... on Page {
isFrontPage
}
}
}
}
md5-f3de54ed5ae0a97baf6316a9baba7040
{
contentNodes(where: {search: "test"}) {
nodes {
__typename
id
title
link
uri
isRevision
... on Page {
isFrontPage
}
}
}
}
md5-df0ace421f3b7d69de9548b91584b75a
{
contentNode(id: "cG9zdDoxNzM5") {
__typename
id
title
link
uri
isRevision
... on Page {
isFrontPage
}
}
}
md5-5be7a1e8044ea4d3d40044a78b186b77
{
contentNode(id: "/2019/12/05/test-5/", idType: URI) {
__typename
id
title
link
uri
isRevision
... on Page {
isFrontPage
}
}
}
md5-87845a7367dc998f352e391a985a6d01
{
contentNode(id: "/test/", idType: URI) {
__typename
id
title
link
uri
isRevision
... on Page {
isFrontPage
}
}
}
md5-cf51e4f27f1f84743cd949dd35863fb5
{
tag(id: "cG9zdF90YWc6Mw==") {
id
name
slug
tagId
}
}
md5-c105fb601a376dd541711de3d2db5ed2
{
tag(id: 3, idType: DATABASE_ID) {
id
name
slug
tagId
}
}
md5-5943b966a1c88bcb238fa4af48fc9321
{
tag(id: "Another Test", idType: NAME) {
id
name
slug
tagId
}
}
md5-6bb1b3342d8a2dcfa7c691f84a214b1f
{
tag(id: "another-test", idType: SLUG) {
id
name
slug
tagId
}
}
md5-da0c06836397d71c7f382f2657cff82a
{
tag(id: "tag/another-test/", idType: URI) {
id
name
slug
tagId
uri
}
}
md5-8268813c2c68e1fce5bbe24f734f089b
{
terms {
nodes {
id
__typename
name
uri
}
}
}
md5-24336542e1fbb87f248697cfcc0a9157
{
terms(where: {search: "test"}) {
nodes {
id
__typename
name
uri
... on Tag {
tagId
}
... on Category {
categoryId
}
}
}
}
md5-90dbae521816525be1442d730f2dae23
{
termNode(id: "cG9zdF90YWc6Mw==") {
__typename
id
name
link
slug
uri
}
}
md5-1e59c2fd516581c09d1693af4dfb9824
{
termNode(id: 3, idType: DATABASE_ID) {
__typename
id
name
link
slug
uri
databaseId
}
}
md5-315baa31cbae1abe887bdb0f58559816
{
termNode(id: "Another Test", idType: NAME, taxonomy: TAG) {
__typename
id
name
link
slug
uri
databaseId
}
}
md5-ed21cf4054c4132ee2a3a03d17f702cb
{
termNode(id: "another-test", idType: SLUG, taxonomy: TAG) {
__typename
id
name
link
slug
uri
databaseId
}
}
md5-c7a2ee25271f29585bcea057fdf2350b
{
termNode(id: "tag/another-test/", idType: URI) {
__typename
id
name
link
slug
uri
databaseId
}
}
md5-5c4f6353d411156d2bd1ec80afcd1610
{
page: nodeByUri(uri: "about/") {
...URI
}
post: nodeByUri(uri: "2019/12/05/test-5/") {
...URI
}
tag: nodeByUri(uri: "tag/8bit/") {
...URI
}
category: nodeByUri(uri: "category/alignment/") {
...URI
}
user: nodeByUri(uri: "author/jasonbahl/") {
...URI
}
}
fragment URI on UniformResourceIdentifiable {
__typename
... on Page {
pageId
}
... on Post {
postId
}
... on Category {
categoryId
}
... on Tag {
tagId
}
... on User {
userId
}
}

Beautiful! Thanks @jasonbahl
So stoked for this. This is a really great feature!
Most helpful comment
The next release I'm working on (#1086) addresses this (the ability to fetch single nodes by various forms of unique identifiers).
Posts
We're deprecating the
$postType.'By'entry points, and have added a newidTypefield and enum for single entry points.This means queries such as the following will still work, but will not show in the Schema documentation, and may be formally removed from the codebase at a later date:
Deprecated Queries