Help with filtering wordpress search results based on user role(s)

Hello. Looking for advice on the best way to go about and how to filter search results based on user role.

My setup: private site with 3 distinct user roles that represent investor groupings. I use the Members plugin to add and assign the roles to users. A user may have more than 1 role. Content (grouped by post category) is restricted and only viewable for roles that have access to it. So, if User 1 is assigned Role A, they will only be able to see/access content that is in a post Category A. If user 2 is assigned Role A and Role B, they will be able to see/access content that is in post categories called “A” and “B”. etc. I use the Content Control plugin to manage the access restrictions.
All good so far. Now I want to be able to have a search box that will allow a user to search a term, but have the results filtered so that only content in categories they have access to will be displayed. Right now results from all categories are displayed (and those that they don’t have access to show the title and meta data with “This content is restricted.” as the excerpt). What I want to achieve is to totally filter out these results so they don’t even show up on the search results page.
I’d prefer to work directly with code in my child theme functions.php file, but will to look at a plugin that I could reverse engineer.

Any thoughts?

  • Patrick Freitas
    • FLS

    Hi Lee

    I hope you are doing well.

    You can take a look at some filter plugins like:
    https://wordpress.org/plugins/search-filter/

    But I don’t believe it would require a filter plugin.

    You can override the search result page, or configure a new result page on your child theme and create the loop using the searched query.

    https://codex.wordpress.org/Creating_a_Search_Page
    https://stackoverflow.com/questions/14802498/how-to-display-wordpress-search-results

    You can create your args based on the user role.

    
    if(userrole..){
    $args = array(
                    's' =>$s,
                    'cat' => 4
                );
    }

    Let us know if you need any further help on this.
    Best Regards
    Patrick Freitas

  • Lee
    • Freelance WP Developer

    Hi Patrick.

    Thanks for the additional link, but I’m still having trouble wrapping my head around this.

    Here is some more detailed info regarding my setup and goals – any help with my specific code would be much appreciated.

    I have 3 post types to be included in the search : post (WP core), page (WP core) and broadcasts (Custom Post Type). ‘Page’ and ‘broadcasts’ do not have any specific taxonomies to be filtered – all results for these can be included. Post type ‘post’ has 3 specific categories, which are based on investment locations – they are Whitby, Oshawa, and Trenton. All ‘posts’ will be assigned only one of these three categories.

    I then have 3 custom roles: investor_oshawa, investor_whitby, and investor_trenton. Every user will be assigned a minimum of one of these roles and a maximum of 3, depending on their specific situation (investments). So, to answer your question they will be known combinations. The possible scenarios would be a maximum of 7:

    1. investor_oshawa
    2. investor_whitby
    3. investor_trenton
    4. investor_oshawa & investor_whitby
    5. investor_oshawa & investor_trenton
    6. investor_whitby & investor_trenton
    7. investor_oshawa & investor_whitby & investor_trenton

    I have set up content restrictions that match the role with the matching post category. An example would be User A is assigned role investor_oshawa. They are therefore able to access all content on post type ‘pages’ and ‘broadcasts’ but are restricted to the post type ‘post’ category of Oshawa. User B is assigned roles investor_oshawa & investor_whitby and therefore are able to access all content on post types ‘pages’ and ‘broadcasts’, but are restricted to the post type ‘post’ categories of Oshawa and Whitby. User C is assigned roles investor_oshawa & investor_whitby & investor_trenton, and therefore would have no restrictions on content.

    These would be the possible ‘if’ scenarios of the search filtering so that results provided would exclude the post type ‘post’ category content that they do not have access to based on their role. I think what I need most help with is the syntax to build the conditional statements of the query as this is my first attempt at creating custom search queries.

    Thanks in advance for your help.

    Lee

  • Patrick Freitas
    • FLS

    Hi Lee

    I hope you are doing well.

    As you have only 7 possible combinations, maybe you can create your args using something like this:

    $user = wp_get_current_user();
    	$roles = ( array ) $user->roles;
    
    	$cap1 = array('investor_oshawa');
    	$cap2 = array('investor_whitby');
    	$cap3 = array('investor_trenton');
    	$cap4 = array('investor_oshawa' , 'investor_whitby');
    	$cap5 = array('investor_oshawa' , 'investor_trenton');
    	$cap6 = array('investor_whitby' , 'investor_trenton');
    	$cap7 = array('investor_oshawa' , 'investor_whitby' , 'investor_trenton');
    
    	if(array_values($cap1) == array_values($roles)){
    		// Only investor_oshawa;
    		$args = array(
    			's' =>$s,
    			'cat' => 4
    		);
    
    	}elseif(array_values($cap2) == array_values($roles)){
    		// Only investor_whitby
    		$args = array(
    			's' =>$s,
    			'cat' => 4
    		);
    	}elseif(array_values($cap3) == array_values($roles)){
    		// Only investor_trenton
    		$args = array(
    			's' =>$s,
    			'cat' => 4
    		);
    	}elseif(array_values($cap4) == array_values($roles)){
    		// investor_oshawa & investor_trenton
    		$args = array(
    			's' =>$s,
    			'cat' => 4
    		);
    	}elseif(array_values($cap5) == array_values($roles)){
    		// investor_oshawa & investor_trenton
    		$args = array(
    			's' =>$s,
    			'cat' => 4
    		);
    
    	}elseif(array_values($cap6) == array_values($roles)){
    		// investor_whitby & investor_trenton
    		$args = array(
    			's' =>$s,
    			'cat' => 4
    		);
    	}elseif(array_values($cap7) == array_values($roles)){
    		// investor_oshawa, investor_whitby & investor_trenton
    		$args = array(
    			's' =>$s,
    			'cat' => 4
    		);
    	}else{
    		// Anything else
    		$args = array(
    			's' =>$s,
    			'cat' => 4
    		);
    	}
    
    	// Your loop goes here

    Inside your args you can use the category parameters:
    https://developer.wordpress.org/reference/classes/wp_query/#category-parameters

    Let us know if you need any further help on this.
    Best Regards
    Patrick Freitas

  • Lee
    • Freelance WP Developer

    Thanks for this Patrick. I’m finally doubling back to this. Found a great series of articles on mastering wp_query on tutsplus, so I’m finally starting to comprehend how this all works together.

    One question, once I have the code hammered out, where does it go? Do I put it in my child theme php functions file? Do I need to create my own search results page? Will this override the default search function of my theme in every instance?

    Thanks for your continued guidance.

    Cheers

    Lee

  • Lee
    • Freelance WP Developer

    Thanks Kasia. I’ve made some progress on this today. I’ll let you know how I get on. Is it possible to turn this into a filter function? I’d rather go that route so I don’t need to style the search results page separately.

    Cheers

    Lee

  • Lee
    • Freelance WP Developer

    Hi community! I finally tamed this beast and was tenacious on ensuring I put it in a child-theme function as opposed creating a separate search template . Thought I would share out the final code in case anyone finds it helpful.

    Thanks to WPMUDEV support for their guidance.

    /// FILTER SEARCH RESULTS BASED ON USER ROLE  
    function search_filter_by_role( $query ) {
      if ( !is_admin() && $query->is_main_query() && !current_user_can('publish_posts') ) { //only run on front-end main query for non admins/post publishers
    	
    	if ( $query->is_search ) { //must be a search query
    		
    		// Create blank arrays to hold applicable cat_ids
    		$broadcasts_pages = array();
    		$investor_posts = array();
    		$include_category = array();
    		
    		// Get User Roles
    		$user = wp_get_current_user();
    		$roles = ( array ) $user->roles;
    		//print_r($roles); //debug
    		
    		//Build array of post catagories IDs based on user role
    		if (in_array("investor_oshawa", $roles)){array_push($include_category, 3 );}
    		if (in_array("investor_whitby", $roles)){array_push($include_category, 1);}
    		if (in_array("investor_trenton", $roles)){array_push($include_category, 4);}
    		//print'<pre> Include CATEGORY ID '.print_r($include_category, true).'</pre>'; //debug
    	
    	
    		//Build Query to retrieve Broadcast and Page Post Type IDs - Non User Conditional
    		$query1 = new WP_Query(array('post_type' => array('broadcasts', 'page'),'fields' => 'ids'));
    		//print'<pre>'.print_r($query1, true).'</pre>';
    		while ( $query1->have_posts() ) : $query1->the_post();
    		array_push($broadcasts_pages, get_the_ID());
    		endwhile;
    		//print'<pre> Broadcasts & Pages '.print_r($broadcasts_pages, true).'</pre>'; //debug
    		wp_reset_postdata();
    		
    		//Build Query to retrieve Investor Restricted Content - Note: array $include_category imploded by WP default
    		$query2 = new WP_Query(array('cat' => $include_category,'fields' => 'ids'));
    		//print'<pre>'.print_r($query1, true).'</pre>';
    		while ( $query2->have_posts() ) : $query2->the_post();
    		array_push($investor_posts, get_the_ID());
    		endwhile;
    		//print'<pre> Investor Posts'.print_r($investor_posts, true).'</pre>'; //debug
    		wp_reset_postdata();
    		
    		// Merge Arrays for Main Search Query
    		$args = array_merge($broadcasts_pages,$investor_posts);
    		//print'<pre> Merged for Arguments'.print_r($args, true).'</pre>'; //debug
    		
    		//Main Query Modifications
    		$query->set( 'post__in', $args);
    		$query->set( 'posts_per_page', 10 );
    			
    	
    	}
      }
    }
    add_action( 'pre_get_posts', 'search_filter_by_role',10 );
    /// END FILTER SEARCH RESULTS BASED ON USER ROLE