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' => '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

Comments

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

  1. Jordan McDonald Avatar
    Jordan McDonald

    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. mvaneijgen Avatar

      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. Jordan McDonald Avatar
        Jordan McDonald

        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. mvaneijgen Avatar

          What is the `graphql_single_name` on your custom post type Event? Is it `event` or is it `Event`?

          1. Jordan McDonald Avatar
            Jordan McDonald

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

  2. Jordan McDonald Avatar
    Jordan McDonald

    Tried this query:

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

  3. Jordan McDonald Avatar
    Jordan McDonald

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

  4. Jordan McDonald Avatar
    Jordan McDonald

    Resolved it. Was my issue. Thanks!

    1. Hatem Avatar
      Hatem

      Can you share with us please ?

      1. mvaneijgen Avatar

        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

  5. Lance Avatar
    Lance

    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?

    1. mvaneijgen Avatar

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

  6. JS Avatar
    JS

    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
    }
    }
    }
    }
    }
    }

Leave a Reply

Your email address will not be published. Required fields are marked *