Skip Navigation

[Resolved] View of children filtered by two or more parents

This thread is resolved. Here is a description of the problem and solution.

Problem: My custom post type is a child of two parent post types. I would like to filter my View of child posts by multiple parents, but the GUI only allows one post relationship filter.

Solution: You can use the wpv_filter_query filter to extend the meta query produced by your View. Child posts are related to parent posts in the postmeta table using the key format "_wpcf_belongs" + parent post type slug + "_id". Example:

add_filter( 'wpv_filter_query', 'multi_parent_filter', 10, 3 );
function multi_parent_filter ( $query, $view_settings, $view_id ) {
  $views = array( 1234, 5678 );
  if( in_array($view_id, $views) ) {
    $args = array(
      'relation' => 'AND',
      array(
        'key' => '_wpcf_belongs_parent-type-slug-1_id',
        'value' => 9876,
        'compare' => '=',
        'type' => 'numeric'
      ),
      array(
        'key' => '_wpcf_belongs_parent-type-slug-2_id',
        'value' => 5432,
        'compare' => '=',
        'type' => 'numeric'
      )
    );
    // add these arguments to your meta query
    $query['meta_query'] = isset($query['meta_query']) ? $query['meta_query'] : [];
    $query['meta_query'][] = $args;
  }
  return $query;
}

Relevant Documentation:
https://toolset.com/documentation/programmer-reference/views-filters/#wpv_filter_query
https://codex.wordpress.org/Class_Reference/WP_Query

This support ticket is created 6 years, 10 months ago. There's a good chance that you are reading advice that it now obsolete.

This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.

Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.

Sun Mon Tue Wed Thu Fri Sat
8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 - -
13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 13:00 – 17:00 - -

Supporter timezone: America/New_York (GMT-04:00)

This topic contains 5 replies, has 3 voices.

Last updated by Beda 6 years, 2 months ago.

Assisted by: Christian Cox.

Author
Posts
#616024

Hi there

I have a need to display a list of Questionnaires. They are children of both Process and Client.
Translated into human language - the usage is : a Client completes Questionnaires related to a Process.

So in the view, I would like to show the Questionnaires that are the children of both a specific Process and a specific Client.

As I see it, the query filter only allow one post relationship filter, and I need two for this (with a boolean AND between).
So for now I have made the post relationship filter on the Process and then I have a conditional output in the loop where I filter for Client.
However, that is probably les DB effective, and also it restricts me from using other view features like "no-items-found".

What can I do differently / better?

#616045

Hi, you can add some custom code that uses the wpv_filter_query API to extend the meta query for this View, and remove the conditionals you have in the results. Child posts are related to each of their parent posts in the postmeta table with a key in the format "_wpcf_belongs_" + parent post type slug + "_id". An example that adds two parent post type filters to a View's query:

add_filter( 'wpv_filter_query', 'multi_parent_filter', 10, 3 );
function multi_parent_filter ( $query, $view_settings, $view_id ) {
  $views = array( 1234, 5678 );
  if( in_array($view_id, $views) ) {
    $args = array(
      'relation' => 'AND',
      array(
        'key' => '_wpcf_belongs_parent-type-slug-1_id',
        'value' => 9876,
        'compare' => '=',
        'type' => 'numeric'
      ),
      array(
        'key' => '_wpcf_belongs_parent-type-slug-2_id',
        'value' => 5432,
        'compare' => '=',
        'type' => 'numeric'
      )
    );
    // add these arguments to your meta query
    $query['meta_query'] = isset($query['meta_query']) ? $query['meta_query'] : [];
    $query['meta_query'][] = $args;
  }
  return $query;
}

If you need to add or remove more parent post types, copy or delete an entire block for each parent post type like this:

      array(
        'key' => '_wpcf_belongs_parent-type-slug-1_id',
        'value' => 9876,
        'compare' => '=',
        'type' => 'numeric'
      ),

Replace 1234, 5678 with a comma-separated list of View IDs where you would like to apply this filter. Replace the keys like '_wpcf_belongs_parent-type-slug-1_id' and '_wpcf_belongs_parent-type-slug-2_id' with the proper keys for each post type, formatted as described above. Replace 9876 and 5432 with the numeric IDs of the parent post for that block's particular post type. If these are not predefined IDs, you must use variables defined by some other criteria. For example if your Users select these parent posts on the front-end with a filter, you must create a custom filter or filters and capture the selected values from the $_POST superglobal. I can help with that if you need assistance.

#617869
Skærmbillede 2018-02-20 kl. 14.19.21.png

Hi Christian
Thanks, this filter is very useful. I actually wish a had searched for this earlier. Could have streamlined our development a bit more.

Am I correct in assuming that this plugin filter adds to the filter defined in Views?
If so, how is the boolean relation between them handled (AND or OR)?

If not, how do I, in the plugin filter, test for a value from the "Post where this View is shown"?

I need the view to return one (1) result of CPT Quest1 where
- _wpcf_belongs_client_id is equal current logged in users client id (got that covered in the plugin) AND
- _wpcf_belongs_process_id is equal the ID of the Process (post) where the view is shown AND
- wpcf_current is equal 1 (current is a Types checkbox field on Quest1)

Thanks.

#618038

Am I correct in assuming that this plugin filter adds to the filter defined in Views?
Yes and if no relationship operator exists yet, the default is "AND".

I need the view to return one (1) result of CPT Quest1 where
- _wpcf_belongs_client_id is equal current logged in users client id (got that covered in the plugin) AND
- _wpcf_belongs_process_id is equal the ID of the Process (post) where the view is shown AND
- wpcf_current is equal 1 (current is a Types checkbox field on Quest1)

It's easier to determine the current User's ID in code than it is to determine the current page in code, so I recommend changing the post relationship query in your View editor to filter the parent Process, set by the current page or post. Then you can use get_current_user_id to get the current User ID. More information about that API here.
https://developer.wordpress.org/reference/functions/get_current_user_id/

add_filter( 'wpv_filter_query', 'multi_parent_filter', 10, 3 );
function multi_parent_filter ( $query, $view_settings, $view_id ) {
  $views = array( 1234, 5678 );
  $user_id = get_current_user_id();
  if( in_array($view_id, $views) ) {
    $args = array(
      'relation' => 'AND',
      array(
        'key' => '_wpcf_belongs_client_id',
        'value' => $user_id,
        'compare' => '=',
        'type' => 'numeric'
      )
    );
    // add these arguments to your meta query
    $query['meta_query'] = isset($query['meta_query']) ? $query['meta_query'] : [];
    $query['meta_query'][] = $args;
  }
  return $query;
}

The "current" field filter and the parent process filter will be maintained from the View editor.

#618248

Hi Christian

Thanks - as you can see in the below code, this is what I ended up with ?
So I have the "current" field filter and the parent post filter in the View, and the below in my plugin as an addition.
Works nicely.

add_filter( 'wpv_filter_query', 'multi_parent_filter', 99, 3 );
function multi_parent_filter ( $query, $view_settings, $view_id ) {
  $views = array( 123, 124 );
  $user_client_id = get_user_meta(get_current_user_id(), 'wpcf-userclientid', true);
  if( in_array($view_id, $views) ) {
    $args = array(
      array(
        'key' => '_wpcf_belongs_client_id',
        'value' => $user_client_id,
      )
    );
    // add these arguments to your meta query
    $query['meta_query'] = isset($query['meta_query']) ? $query['meta_query'] : [];
    $query['meta_query'][] = $args;
  }
  return $query;
}
#1129605