Skip Navigation

[Resolved] Query filter fallback for a view

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

Problem: I have a View and I want to ensure that 4 results are always displayed. I can set a limit of 4, but I would also like to know how to append random results as needed if the number of results is less than 4.

Solution: Use the Views Filter wpv_filter_query_post_process to manipulate the result set programmatically. Use WP_Query to fetch random results that aren't included in the results already, and then append those to the current results. Example:

add_filter( 'wpv_filter_query_post_process', 'nh_modify_related_gt_query', 10, 3 );
 
function nh_modify_related_gt_query( $query, $view_settings, $view_id ) {
    if( $view_id = '22313' ) { // Applies to "Related Glossary Terms (4)" view
        if ( sizeof( $query->posts ) < 4 ) { // if the query has less than 4 related terms
            $fillsize = 4 - sizeof( $query->posts );
            $post_ids = wp_list_pluck( $query->posts, 'ID' );
            $args = array(
                'post_type'         => 'glossary',
                'posts_per_page'    => $fillsize,
                'post__not_in'      => $post_ids,
                'orderby'           => 'rand',
                'no_found_rows'     => true
            );
 
            $fillquery = new WP_Query( $args );
            $initposts = $query->posts;
            $randposts = $fillquery->posts;
            $filled_terms = array_merge($initposts, $randposts);
 
            $query->posts = $filled_terms; // add the random posts at the end of the posts result array
            $query->found_posts = 4; // modify the count of found posts
            $query->post_count = 4; // modify the count of displayed posts
        }
    }
    return $query;
}

Relevant Documentation:
https://toolset.com/documentation/programmer-reference/views-filters/#wpv_filter_query_post_process
https://developer.wordpress.org/reference/classes/wp_query/

This support ticket is created 4 years, 3 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 10 replies, has 2 voices.

Last updated by bastienB 4 years, 2 months ago.

Assisted by: Christian Cox.

Author
Posts
#1471803

Hello guys,

This is a follow-up for this thread: https://toolset.com/forums/topic/create-a-related-articles-list-at-the-end-of-single-page-cpt/

So we have a view that's filtered based on the Tag of the page where the view is displayed.

It works well when we have the actual relationships configured but we'd like to make sure there is always 4 posts displayed, even if no tags are configured.

So for example, if there are only 2 posts with the same Tags, the view would display those and two other random Glossary Term and if there are no posts with a Tags relation then it would just display 4 random Glossary Terms.

Is there a way to do that?

Thank you!

#1471943

Hi, there's not an easy way to accomplish this from wp-admin, but we do offer a PHP API that can be used to modify the result set on-the-fly based on the number of returned results. The API is called wpv_filter_query_post_process, and we have documentation available here: https://toolset.com/documentation/programmer-reference/views-filters/#wpv_filter_query_post_process

Here's a commented example of this API in use to ensure that at least 1 post is always returned:

add_filter( 'wpv_filter_query_post_process', 'tssupp_modify_empty_query', 10, 3 );
 
function tssupp_modify_empty_query( $query, $view_settings, $view_id ) {
    if ( empty( $query->posts ) ) { // if the query found no posts
        $default_post = get_post(1); // get the post with ID equal to 1
        $query->posts = array( $default_post ); // add the default post to the posts result array
        $query->found_posts = 1; // modify the count of found posts
        $query->post_count = 1; // modify the count of displayed posts
    }
    return $query;
}

I'm not sure of your level of PHP knowledge, so let me know if you need more guidance on customizing this code for your needs.

#1473599

Hey Christian,

Thanks for the link and example.

I'm guessing this would go in our child-theme functions.php, correct?

The example you provided is rather straightforward but what if we don't want specific posts (random glossary terms) and we'd like to keep the queried posts, if any found and there's less than 4?

I'm not entirely sure how I would merge, let's say for example, the first two posts returned that had a matching Tag with two other random posts.

Would something like that work?

add_filter( 'wpv_filter_query_post_process', 'nh_modify_related_gt_query, 10, 3 );
  
function nh_modify_related_gt_query( $query, $view_settings, $view_id ) {
    if( $view_id = '22313' ) { // Applies to "Related Glossary Terms (4)" view
        if ( sizeof( $query->posts ) < 4 ) { // if the query has less than 4 related terms
            $fillsize = 4 - sizeof( $query->posts )
            // Do something to query $fillsize random Glossary Term in var $randomqt

            $query->posts = array( $randomqt ); // add the random posts at the end of the posts result array
            $query->found_posts = 4; // modify the count of found posts
            $query->post_count = 4; // modify the count of displayed posts
       }
    }
    return $query;
}

I you could just provide some help for the random query part that would be fantastic!

Thank you!

#1473739

Yes I think you're on the right track. Here's an example showing how to sort a query randomly:
https://wordpress.stackexchange.com/questions/115130/wp-query-random

$args = array(
    'category_name'  => 'cat1',
    'posts_per_page' => 5,
    'orderby'        => 'rand',
);
$pc = new WP_Query( $args ); 

Info about ordering a WP_Query:
https://developer.wordpress.org/reference/classes/wp_query/#order-orderby-parameters

You should probably add a post__not_in clause, because you don't want duplicates. You would have to create an array of post IDs from the existing results, then pass that array into post__not_in. More information about WP_Query arguments here: https://developer.wordpress.org/reference/classes/wp_query/#post-page-parameters

Careful here - looks like this will overwrite the existing posts instead of appending to them:

$query->posts = array( $randomqt ); // add the random posts at the end of the posts result array

Maybe array_merge those arrays? https://www.php.net/manual/en/function.array-merge.php

#1473851

Hey Christian,

Thanks again for the assistance.

So here's the code I've got but unfortunately it's causing an Error 500:

add_filter( 'wpv_filter_query_post_process', 'nh_modify_related_gt_query', 10, 3 );

function nh_modify_related_gt_query( $query, $view_settings, $view_id ) {
	if( $view_id = '22313' ) { // Applies to "Related Glossary Terms (4)" view
		if ( sizeof( $query->posts ) < 4 ) { // if the query has less than 4 related terms
			$fillsize = 4 - sizeof( $query->posts );
			$post_ids = wp_list_pluck( $query->posts, 'ID' );
			$post_ids_string = implode( ',', $post_ids );
			// Do something to query $fillsize random Glossary Term in var $randomqt
			$args = array(
				'post_type'			=> 'glossary',
				'posts_per_page'	=> $fillsize,
				'post__not_in'		=> $post_ids_string,
				'orderby'			=> 'rand',
				'no_found_rows'		=> true
			);
			
			$fillquery = new WP_Query( $args );
			$filled_terms = array_merge($query->posts, $fillquery->posts);
			wp_reset_postdata();
			
			$query->posts = array( $filled_terms ); // add the random posts at the end of the posts result array
			$query->found_posts = 4; // modify the count of found posts
			$query->post_count = 4; // modify the count of displayed posts
		}
	}
	return $query;
}

Here's the error:

PHP Fatal error: Uncaught Error: __clone method called on non-object in /.../wp-content/plugins/wp-views/embedded/inc/wpv.class.php:2453\nStack trace:\n#0 /.../wp-content/plugins/wp-views/embedded/inc/wpv.class.php(2055): WP_Views->render_view('22313', '39b96018ab57d3c...')\n#1 /.../wp-content/plugins/wp-views/embedded/inc/wpv.class.php(638): WP_Views->render_view_ex('22313', '39b96018ab57d3c...')\n#2 /.../wp-includes/shortcodes.php(325): WP_Views->short_tag_wpv_view(Array, '', 'wpv-view')\n#3 [internal function]: do_shortcode_tag(Array)\n#4 /.../wp-includes/shortcodes.php(199): preg_replace_callback('/\\\\[(\\\\[?)(easy\\\\-...', 'do_shortcode_ta...', '<style>@media a...')\n#5 /.../wp-includes/class-wp-hook.php(288): do_shortcode('<style>@media a...')\n#6 /.../wp-includes/plugin.php(206): WP_Hook->apply_filters('<style>@media a...', Array)\n#7 /.../wp in /.../wp-content/plugins/wp-views/embedded/inc/wpv.class.php on line 2453

Waiting for your feedback.

#1473855

I changed the code slightly and now there no more Error 500 but the results are still empty...
EDIT: My bad, the error 500 is still there and the page glossary term page is broken.

Here's the new code:

add_filter( 'wpv_filter_query_post_process', 'nh_modify_related_gt_query', 10, 3 );

function nh_modify_related_gt_query( $query, $view_settings, $view_id ) {
	if( $view_id = '22313' ) { // Applies to "Related Glossary Terms (4)" view
		if ( sizeof( $query->posts ) < 4 ) { // if the query has less than 4 related terms
			$fillsize = 4 - sizeof( $query->posts );
			$post_ids = wp_list_pluck( $query->posts, 'ID' );
			$post_ids_string = implode( ',', $post_ids );
			// Do something to query $fillsize random Glossary Term in var $randomqt
			$args = array(
				'post_type'			=> 'glossary',
				'posts_per_page'	=> $fillsize,
				'post__not_in'		=> $post_ids_string,
				'orderby'			=> 'rand',
				'no_found_rows'		=> true
			);
			
			$fillquery = new WP_Query( $args );
			$initposts[] = $query->posts;
			$randposts[] = $fillquery->posts;
			$filled_terms = array_merge($initposts, $randposts);
			wp_reset_postdata();
			
			$query->posts = array( $filled_terms ); // add the random posts at the end of the posts result array
			$query->found_posts = 4; // modify the count of found posts
			$query->post_count = 4; // modify the count of displayed posts
		}
	}
	return $query;
}

Probably something to do with how the custom query is built...

Waiting for your feedback!

#1473875

The value for post__not_in should be an array, not a comma-separated string. A comma-separated string will break the main $args array syntax.

'post__not_in'      => $post_ids_string,

You can just use $post_ids here, since it's the array of IDs.

You probably don't need the reset post data here, I would comment it out:

wp_reset_postdata();

Main issue: the $filledterms variable is already an array, so there's no need to wrap it in another array:

$query->posts = array( $filled_terms );
#1473905

Hey Christian,

Thanks for the cues, unfortunately I'm still getting the same error.

Here's the latest code tested:

add_filter( 'wpv_filter_query_post_process', 'nh_modify_related_gt_query', 10, 3 );

function nh_modify_related_gt_query( $query, $view_settings, $view_id ) {
	if( $view_id = '22313' ) { // Applies to "Related Glossary Terms (4)" view
		if ( sizeof( $query->posts ) < 4 ) { // if the query has less than 4 related terms
			$fillsize = 4 - sizeof( $query->posts );
			$post_ids = wp_list_pluck( $query->posts, 'ID' );
			$args = array(
				'post_type'			=> 'glossary',
				'posts_per_page'	=> $fillsize,
				'post__not_in'		=> $post_ids,
				'orderby'			=> 'rand',
				'no_found_rows'		=> true
			);

			$fillquery = new WP_Query( $args );
			$initposts[] = $query->posts;
			$randposts[] = $fillquery->posts;
			$filled_terms = array_merge($initposts, $randposts);
			//wp_reset_postdata();

			$query->posts = $filled_terms; // add the random posts at the end of the posts result array
			$query->found_posts = 4; // modify the count of found posts
			$query->post_count = 4; // modify the count of displayed posts
		}
	}
	return $query;
}

Thanks again for your help with this.

Waiting for your feedback!

#1475107

Remove the bracket notation here. These are new variable assignments:

$initposts = $query->posts;
$randposts = $fillquery->posts;
#1475239

Thanks for that Christian, no more errors!

However for some odd reason our archive is affected by the function.

The Glossary Terms archive (View ID 22253) is configured to loop through Taxonomy terms using a Taxonomy view (ID 22249) which loops through items with a child-post view (ID 22251).

So there's nowhere in the Archive the use of the view with the ID 22313, which is used to display 4 related Glossary Terms. Since the function is pretty much wrapped in a conditional to check for the view 22313 I'm not sure what's going on here.

Waiting for your feedback!

#1475249

Hey Christian,

Looks like this was some sort of caching issue... I waited a bit and the Archive page returned to normal.

Thanks again for your help!

This ticket is now closed. If you're a WPML client and need related help, please open a new support ticket.