Query posts based on Advanced Custom Field values by Registering a Custom “where” Argument

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' => 'ID',
        'description' => __('The ID 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) {

    $post_object_id = $args['where']['postObjectId'];

    if (isset($post_object_id)) {
        $query_args['meta_query'] = [
            [
                'key' => 'myCustomField',
                'value' => $post_object_id,
                '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

Join the Conversation

12 Comments

  1. 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

    1. 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?

      1. 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);

          1. This is what I have:
            ‘graphql_single_name’ => ‘event’,
            ‘graphql_plural_name’ => ‘events’,

  2. Tried this query:

    query MyQuery {
    events(where: {eventAudience: “PUBLIC”}) {
    edges {
    node {
    insiderEvent {
    eventAudience
    eventCity
    eventCtaAriaLabel
    eventDescription
    eventEndDate
    eventImageAltText
    eventIsGlobal
    eventRegistrationLink
    eventRegistrationLinkText
    eventStartDate
    fieldGroupName
    }
    }
    }
    }
    }

  3. 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);

      1. 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

  4. 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?

Leave a comment

Your email address will not be published.