If you manage custom fields in WordPress using Advanced Custom Fields, and you want to use WPGraphQL to get a list of posts filtering by the ACF field value, you’ll need to implement a few things in your themes functions.php
.
Summary:
- Register a new “where” argument to the WPGraphQL Posts connection
- Filter the Posts connection resolver to account for this new argument
Register the new “where” argument:
First you need to create a add_action
on graphql_register_types
that will look something like the following code snippet. Here we register a field on the RootQueryToMyCustomPostTypeConnectionWhereArgs
where you can define MyCustomPostType
as your post type. The type we register will be an ID
(This can also be of type Boolean
, Float
, Integer
, orString
) for my case I wanted to get only posts that where connected to an other post via the ACF post object field (the field was set to return only the Post ID).
Filter the connection resolver
add_action('graphql_register_types', function () {
$customposttype_graphql_single_name = "MyCustomPostType";
register_graphql_field('RootQueryTo' . $customposttype_graphql_single_name . 'ConnectionWhereArgs', 'postObjectId', [
'type' => 'Int',
'description' => __('The databaseId of the post object to filter by', 'your-textdomain'),
]);
});
Next we have to create an add_filter
to graphql_post_object_connection_query_args
. If you are familiar with WordPress loops via WP_Query
, here we set the $query_args
like we would do on any other loop, but we check for your custom where:
.
add_filter('graphql_post_object_connection_query_args', function ($query_args, $source, $args, $context, $info) {
if (isset($args['where']['postObjectId'])) {
$query_args['meta_query'] = [
[
'key' => 'myCustomField',
'value' => (int) $args['where']['postObjectId'],
'compare' => '='
]
];
}
return $query_args;
}, 10, 5);
The key
will be the name of the field, the value
will be the value you will give the postObjectId: "123"
in your query, speaking of the query that will ook something like
query GetMyCustomPostType {
MyCustomPostType(where: {postObjectId: "123"}) {
nodes {
title
}
}
}
This will get all your MyCustomPostType
where myCustomField = 123
Hi, thanks for the post. It doesn’t work for me however. Do I need a certain version of WP Graph GL and WordPress?
Thanks
When writing this I’d version `0.3.1` wp-graphql-acf and version `0.8.2` of wp-graphql (just updated to `0.8.3` with its still working). What does your code look like and what do you get while querying your data? Can you share your end-point with the query that is not working?
Here is the endpoint: https://wipaffirmadev.trafficmanager.net/graphql (it has an SSL issue so you will have to proceed past the warning). The error is
{
“errors”: [
{
“message”: “Field \”eventAudience\” is not defined by type RootQueryToEventConnectionWhereArgs.”,
“category”: “graphql”,
“locations”: [
{
“line”: 2,
“column”: 18
}
]
}
]
The code is below. My custom field is called event_audience in WordPress settings. My field group is called insiderEvent and that is showing up in the Graphiql explorer. I see eventAudience is listed there too but in wordPress it is event_audience. I have tried both in the code below as the “kye” but neither work.
add_action(‘graphql_register_types’, function () {
$customposttype_graphql_single_name = “event”;
register_graphql_field(‘RootQueryTo’ . $customposttype_graphql_single_name . ‘ConnectionWhereArgs’, ‘eventAudience’, [
‘type’ => ‘string’,
‘description’ => __(‘The eventAudience of the Event custom post to filter by’, ‘Event’),
]);
});
add_filter(‘graphql_post_object_connection_query_args’, function ($query_args, $source, $args, $context, $info) {
$post_object_id = $args[‘where’][‘eventAudience’];
if (isset($post_object_id)) {
$query_args[‘meta_query’] = [
[
‘key’ => ‘eventAudience’,
‘value’ => $eventAudience,
‘compare’ => ‘=’
]
];
}
return $query_args;
}, 10, 5);
What is the `graphql_single_name` on your custom post type Event? Is it `event` or is it `Event`?
This is what I have:
‘graphql_single_name’ => ‘event’,
‘graphql_plural_name’ => ‘events’,
Tried this query:
query MyQuery {
events(where: {eventAudience: “PUBLIC”}) {
edges {
node {
insiderEvent {
eventAudience
eventCity
eventCtaAriaLabel
eventDescription
eventEndDate
eventImageAltText
eventIsGlobal
eventRegistrationLink
eventRegistrationLinkText
eventStartDate
fieldGroupName
}
}
}
}
}
The custom field is of type SELECT. Is this ok? I am registering it as a string in ‘register_graphql_field’ because the output would be a string after a value has been selected.
I had some issues with the code above and fixed something. Currently what I am trying is.
add_action(‘graphql_register_types’, function () {
$customposttype_graphql_single_name = “event”;
register_graphql_field(‘RootQueryTo’ . $customposttype_graphql_single_name . ‘ConnectionWhereArgs’, ‘eventAudience’, [
‘type’ => ‘String’,
‘description’ => __(‘The eventAudience of the Event custom post to filter by’, ‘Event’),
]);
});
add_filter(‘graphql_post_object_connection_query_args’, function ($query_args, $source, $args, $context, $info) {
$eventAudienceName = $args[‘where’][‘eventAudience’];
if (isset($eventAudienceName)) {
$query_args[‘meta_query’] = [
[
‘key’ => ‘eventAudience’,
‘value’ => $eventAudienceName,
‘compare’ => ‘=’
]
];
}
return $query_args;
}, 10, 5);
Resolved it. Was my issue. Thanks!
Can you share with us please ?
It probably was the fact that the types are typed with a capital letter at first so it is Boolean, Float, Integer, String not boolean, float, integer, string
Thanks, super helpful!
Although, now I’m fumbling around trying to figure out how to query based on two acf fields. In other words, if `(where: {field1: $value1, field2: $value2})`.
I’ve tried several things but cannot seem to get it to work. Any pointers?
@Lance what have you already tried?
I’ve never tried it and don’t have the time at the moment to set everything up for testen, but I would figure it would look something like:
(moved code to Gist)
https://gist.github.com/mvaneijgen/a05f3205b9fe45936f8fb86978f08667
You could probably also try and make it more dynamic by updating the `$query_args` if only certain values are present.
Hi! Thanks for the post!
I have my regular Post Type with an ACF Called “campus” which it’s an object field pointing to my custom post type Campus:’graphql_single_name’ => ‘campus’, ‘graphql_plural_name’ => ‘campuses’
I have hours wrestling with this but not luck so far…
————————————
add_action(‘graphql_register_types’, function () {
$customposttype_graphql_single_name = “Post”;
register_graphql_field(‘RootQueryTo’ . $customposttype_graphql_single_name . ‘ConnectionWhereArgs’, ‘campus’, [
‘type’ => ‘String’,
‘description’ => __(‘The Campus of the post object to filter by’, ‘Post’),
]);
});
add_filter(‘graphql_post_object_connection_query_args’, function ($query_args, $source, $args, $context, $info) {
$post_object_campus = $args[‘where’][‘campus’];
if (isset($post_object_campus)) {
$query_args[‘meta_query’] = [
[
‘key’ => ‘campus’,
‘value’ => $post_object_campus,
‘compare’ => ‘=’,
]
];
}
return $query_args;
}, 10, 5);
———– My Query ————-
query myQuery {
posts(where: {campus: “global”}) {
nodes {
title
postDetails {
campus {
… on Campus {
id
title
}
}
}
}
}
}