Skip Navigation

[Resolved] View filter by multiple parents

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

Problem: I have a post type that is a child of two parent post types. I would like to filter a View of my child posts by post relationship, including both parent post types filters. I would like to pass the parent IDs into the View filters as URL parameters.

Solution: Add hidden input fields that access the URL parameters using the custom wpv-post-params shortcode. Then modify the query using wpv_filter_query to create a combined meta query using both parent types.

// access any url parameter
// [wpv-post-param var="someparam"]
add_shortcode( 'wpv-post-param', 'wpv_post_param_shortcode' ); 
function wpv_post_param_shortcode( $atts ) {
  if ( !empty( $atts['var'] ) ) {
    $var = (array)$_GET[$atts['var']];
    return esc_html( implode( ', ', $var ) );
  }
}

// combine parent post type relationship filters
add_filter( 'wpv_filter_query', 'filter_both_parent_types', 10, 3 );
function filter_both_parent_types ( $query, $view_settings, $view_id ) {
  if( $view_id == 1234 ) {
    $selected_parent1 = isset($_GET['bookid']) ? $_GET['bookid'] : null;
    $selected_parent2 = isset($_GET['authorid']) ? $_GET['authorid'] : null;
    $args = array(
      'relation' => 'AND',
      array(
        'key' => '_wpcf_belongs_book_id',
        'value' => $selected_parent1,
        'compare' => '=',
        'type' => 'numeric'
      ),
      array(
        'key' => '_wpcf_belongs_author_id',
        'value' => $selected_parent2,
        '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

This support ticket is created 7 years, 1 month 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 2 voices.

Last updated by John 7 years, 1 month ago.

Assisted by: Christian Cox.

Author
Posts
#575140

I have a many to many relationship:

Book <-- Contributor --> Author

A book can have multiple authors, an author can have multiple books.

I know the ID of the book, and I know the ID of the author (post id). What I need to be able to do is create a view that finds the contributor record between them.

For example, /contributor-page?bookid=123&authorid=432

Take this and feed this into a view that returns the contributor record that states:

Author ID 432 contributed to Book ID 123.

The problem is that in the view settings, I can declare "is a child of" only once.

Is there a way to add a second filter through some other means? Why can't I just reference the actual data in the field (e.g. wcfp_postname or wherever that data is stored)?

#575188

Is there a way to add a second filter through some other means?
If you add one post relationship filter, let's say author ID, then you can add conditional HTML in that View's output that will test the book parent against a URL parameter. This shortcode will allow you to access any URL parameter:

add_shortcode( 'wpv-post-param', 'wpv_post_param_shortcode' );

function wpv_post_param_shortcode( $atts ) {
  if ( !empty( $atts['var'] ) ) {
    $var = (array)$_GET[$atts['var']];
    return esc_html( implode( ', ', $var ) );
  }
}

Then you can use conditional code like this:

[wpv-conditional if="( '[wpv-post-id id='$book']' eq '[wpv-post-param var='bookid']' )"]
  This will be displayed for the matching intermediary post.
[/wpv-conditional]

Why can't I just reference the actual data in the field (e.g. wcfp_postname or wherever that data is stored)?
The reference between a parent and child post is stored as a hidden postmeta value on the child post, so it's not accessible in the GUI to be assigned to a filter. If you want to access that field in PHP, the key syntax is "_wpcf_belongs_parentslug_id". So if your parent slug is book, the syntax is "_wpcf_belongs_book_id".

We're currently making some big changes to the way Many to Many relationships are handled and displayed, so this process is going to be smoother in upcoming releases. There's currently a beta version of the Types side of this available, but there's not yet a beta version showing how this will be implemented in Views. Let me know if you have additional questions here.

#575228

Hey Christian,

Thanks for the quick reply. I am aware of the workaround you've suggested, but unfortunately, I need to know when no results are returned.

E.g. If Author A has not contributed to Book B, then I need to be able to create a line that says "Author A has not contributed to Book B" (using the no results found within the view).

The conditional would result in the not generating the "no results" segment.

I am closely following v2.3, but I have to solve this one immediately.

I've tried feeding the IDs of both parents into a view, but this gives all related posts to both (outer join), when I need an inner join...

Any other ideas? Thanks again!

#575232

I came up with an extremely hacky solution. Is this safe to use?
(it appears to work)

[wpv-view name="testtest" parent1="10243" parent2="10723"]

testtest is a view selecting contributors, limited to related authors (parent 1)
-this view calls another view inline (see below), feeding the list of ids from this view

testtest2 is a view selectin contributors, limited to related books (parent 2)
(this view is fed a list of IDs from view1, in addition to the parent2 id

(view testtest)

[wpv-layout-start]
	[wpv-items-found]
	<!-- wpv-loop-start -->
[wpv-view name="testtest2" parent2="[wpv-attribute name="parent2"]" ids="
	<wpv-loop>
		[wpv-post-id],
	</wpv-loop>"]
	<!-- wpv-loop-end -->
	[/wpv-items-found]
	[wpv-no-items-found]
		<strong>[wpml-string context="wpv-views"]No items found[/wpml-string]</strong>
	[/wpv-no-items-found]
[wpv-layout-end]

I was a bit surprised that views would allow me to nest an entire loop statement into an argument to another view. Is this a viable solution or am I apt to run into issues down the line?

Any cleaner ideas/solutions would be greatly appreciated... thanks again!

#575234

I think I was drafting my response while you were writing yours. The better solution is to filter the query using wpv_filter_query. You can add two hidden input fields into your View's filter controls. One can capture the value of parent A and the other can capture the value of parent B, using the wpv-post-param shortcode I mentioned earlier. In the Filter Controls panel, add this code inside the wpv-filter-controls tags:

<input type="hidden" value="[wpv-post-param var='bookid']" name="bookid" /><input type="hidden" value="[wpv-post-param var='authorid']" name="authorid" />

Then in your functions.php file, add the following code:

add_filter( 'wpv_filter_query', 'filter_both_parent_types', 10, 3 );
function filter_both_parent_types ( $query, $view_settings, $view_id ) {
  if( $view_id == 1234 ) {
    $selected_parent1 = isset($_GET['bookid']) ? $_GET['bookid'] : null;
    $selected_parent2 = isset($_GET['authorid']) ? $_GET['authorid'] : null;
    $args = array(
      'relation' => 'AND',
      array(
        'key' => '_wpcf_belongs_book_id',
        'value' => $selected_parent1,
        'compare' => '=',
        'type' => 'numeric'
      ),
      array(
        'key' => '_wpcf_belongs_author_id',
        'value' => $selected_parent2,
        '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;
}

Change "1234" to match your View's ID.

#576226

Awesome thanks so much Christian. I'll give this a shot and report back if I run into any issues.