Comparing arrays with meta_query in pre_get_posts

I’m working on a form for filtering a list of posts using custom fields created with the Advanced Custom Fields plugin. Because of the form, I’m using the pre_get_posts action to change the query via GET requests. (following code references are either PHP or dumped from print_r())

I set the meta_query like this:

Read More
$query->set('meta_query',$filter);

and $filter looks like this:

Array
(
    [0] => Array
        (
            [key] => delivery_method
            [value] => Array
                (
                    [0] => Online
                    [1] => Scheduled

                )

            [compare] => IN
        )
)

The custom field that I am querying is structured like this:

Array (
    [delivery_method] => Array (
        [0] => Online
        [1] => Scheduled
    )
)

When I look for posts with [compare] => IN (as above), no posts are returned. When I look for posts with [compare] => NOT IN, all of the posts are returned.

I am trying to return only those posts which have a specific “delivery method”. Is there a way to compare the two arrays that I missed? or do I have to somehow explode one of the arrays and compare individual values against an array?

Related posts

Leave a Reply

2 comments

  1. The ACF Documentation recommends checking the values individually rather than simultaneously using an array.

    The following code is from the ACF Documentation for the Checkbox field type:

    http://www.advancedcustomfields.com/resources/field-types/checkbox/

    /*
    *  Query posts for a checkbox value.
    *  This method uses the meta_query LIKE to match the string "red" to the database value a:2:{i:0;s:3:"red";i:1;s:4:"blue";} (serialized array)
    *  The above value suggests that the user selected "red" and "blue" from the checkbox choices
    */
    
    $posts = get_posts(array(
        'meta_query' => array(
            array(
                'key' => 'field_name', // name of custom field
                'value' => '"red"', // matches exaclty "red", not just red. This prevents a match for "acquired"
                'compare' => 'LIKE'
            )
        )
    ));
    

    Therefore the query in pre_get_posts should look like this:

    $filter = array(
        array(
            'key' => 'delivery_method'
            'value' => '"Online"'
            'compare' => 'LIKE'
        ),
        array(
            'key' => 'delivery_method'
            'value' => '"Scheduled"'
            'compare' => 'LIKE'
        )
    )
    
    $query->set('meta_query',$filter);
    
  2. If I am correct, you have a field that contain an array, to be clear, something that you can save using:

    add_post_meta( $postid, 'delivery_method', array('Online', 'Scheduled') );
    

    Then you want to query posts where field ‘delivery_method’ = array( 'Online', 'Scheduled').

    The problem is that a meta query like the yours:

    $meta_query = array(
      array(
        'key' => 'delivery_method',
        'value' => array( 'Online', 'Scheduled' ),
        'compare' => 'IN'
      )
    );
    

    returns posts having the ‘deliver_method’ key set to ‘Online’ (string) or ‘Scheduled’ (string) or both, but your post has the key ‘deliver_method’ saved as array, so its value is serialized by WordPress before being saved in database, and you can’t query for a serialized value using an unserialized array…

    So, if you want to store different delivery methods, it’s fairly better if you use multiple values for same key, instead of a key with multiple values, e.g.

    add_post_meta( $postid, 'delivery_method', 'Online' );
    add_post_meta( $postid, 'delivery_method', 'Scheduled' );
    

    In this way, using proper args, you’ll be able to get posts having one of the methods, or both, depending on your needs.

    I sincerly don’t know how to implement this using ACF, and however the plugin-specific way is off topic for this site, but I think the concept is simple and you can simply apply on that plugin.

    A dirty hack for the specific case is query using as value the serialized value

    $meta_query = array(
      array(
        'key' => 'delivery_method',
        'value' => serialize ( array( 'Online', 'Scheduled' ) )
      )
    );
    

    This meta query returns the posts having both methods saved as array.