Skip to content

Instantly share code, notes, and snippets.

@boonebgorges
Created May 8, 2012 20:13
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save boonebgorges/2638943 to your computer and use it in GitHub Desktop.
Save boonebgorges/2638943 to your computer and use it in GitHub Desktop.
Limit a bp_has_groups() loop to groups matching a groupmeta key/value pair
<?php
/**
* This is a quick and dirty class to work around the fact that bp_has_groups() does not have a
* meta_query parameter (or even an 'in' parameter). Usage:
*
* 1) Just before you fire up your bp_has_groups() loop, instantiate the BP_Groups_Meta_Filter
* class, with parameters $key and $value
* 2) Do your groups loop as normal
* 3) When you've closed the bp_has_groups() loop (endif;), call the method remove_filters() just
* to be safe.
*
* EXAMPLE
* Here's how you would run a bp_has_groups() loop that would only show groups that had the meta
* key/value: 'favorite_gum' => 'Juicy Fruit'
*
* $meta_filter = new BP_Groups_Meta_Filter( 'favorite_gum', 'Juicy Fruit' );
*
* // Note that you can pass whatever arguments you want to bp_has_groups(), as usual
* if ( bp_has_groups() ) :
* while ( bp_groups() ) :
* bp_the_group();
* // Do your template stuff here
* endwhile;
* endif;
*
* // Make sure that other loops on the page are clean
* $meta_filter->remove_filters();
*/
class BP_Groups_Meta_Filter {
protected $key;
protected $value;
protected $group_ids = array();
function __construct( $key, $value ) {
$this->key = $key;
$this->value = $value;
$this->setup_group_ids();
add_filter( 'bp_groups_get_paged_groups_sql', array( &$this, 'filter_sql' ) );
add_filter( 'bp_groups_get_total_groups_sql', array( &$this, 'filter_sql' ) );
}
function setup_group_ids() {
global $wpdb, $bp;
$sql = $wpdb->prepare( "SELECT group_id FROM {$bp->groups->table_name_groupmeta} WHERE meta_key = %s AND meta_value = %s", $this->key, $this->value );
$this->group_ids = wp_parse_id_list( $wpdb->get_col( $sql ) );
}
function get_group_ids() {
return $this->group_ids;
}
function filter_sql( $sql ) {
$group_ids = $this->get_group_ids();
if ( empty( $group_ids ) ) {
return $sql;
}
$sql_a = explode( 'WHERE', $sql );
$new_sql = $sql_a[0] . 'WHERE g.id IN (' . implode( ',', $group_ids ) . ') AND ' . $sql_a[1];
return $new_sql;
}
function remove_filters() {
remove_filter( 'bp_groups_get_paged_groups_sql', array( &$this, 'filter_sql' ) );
remove_filter( 'bp_groups_get_total_groups_sql', array( &$this, 'filter_sql' ) );
}
}
?>
@boonebgorges
Copy link
Author

Yes, it's working fine for me, though it's something I wrote in about 15 minutes, so there are probably bugs.

Doesn't matter where you put the class, as long as you instantiate it at the right time (as in your example). functions.php of your theme should be fine.

If it's not working, you might try finding the place in buddypress/bp-groups/bp-groups-classes.php where the filters 'bp_groups_get_paged_groups_sql' and 'bp_groups_get_total_groups_sql' are applied. Try echoing the sql string before and after it's been filtered, to make sure that these filters are actually getting applied. If so, and they're still not working, please copy them into a comment here so that I can see if anything obvious jumps out at me.

@Davidlab
Copy link

Davidlab commented Jun 4, 2012

This is exactly what I was looking for! I tried it and it works great. How would I make it so if there is no match no groups are returned? right now it returns all the groups if there is no match and only filters the groups of there is a match. I played with some if statements before the loop....like, if object has value then loop...if not then display "no matches". Could not get it to work, but I am rusty with php. Thanks for any help you can give me.

@boonebgorges
Copy link
Author

@Davidlab - Try changing the filter_sql() method to:

function filter_sql( $sql ) {
    $group_ids = $this->get_group_ids();
    if ( empty( $group_ids ) ) {
        $group_ids = array(0);
    }

    $sql_a = explode( 'WHERE', $sql );

    $new_sql = $sql_a[0] . 'WHERE g.id IN (' . implode( ',', $group_ids ) . ') AND ' . $sql_a[1];

    return $new_sql;
}

@Davidlab
Copy link

Davidlab commented Jun 4, 2012

beautiful...works perfect! thanks.

@aaclayton
Copy link

Hey Boone, thanks very much for this. I know this snippet has been dormant for a while, but this fits perfectly the exact project I am trying to implement. Unfortunately, I'm having a problem which I have been unable to solve, I was hoping you could weigh in with your 2c.

The problem I'm having is that for some reason the filters:

add_filter( 'bp_groups_get_paged_groups_sql', array( &$this, 'filter_sql' ) );
add_filter( 'bp_groups_get_total_groups_sql', array( &$this, 'filter_sql' ) );

are not properly passing the $new_sql string (which is being generated correctly!) into the BP_Groups_Group::get() function. For, example, I have:

$new_sql = "SELECT group_id FROM wp_bp_groups_groupmeta WHERE g.id IN (2) AND meta_key = 'my_key' AND meta_value = 'my_value'"

but, the applied query is still processed as:

$paged_groups_sql = "SELECT g.*, gm1.meta_value AS total_member_count, gm2.meta_value AS last_activity FROM wp_bp_groups_groupmeta gm1, wp_bp_groups_groupmeta gm2, wp_bp_groups g WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' ORDER BY last_activity DESC LIMIT 0, 20"

$total_groups_sql = "SELECT COUNT(DISTINCT g.id) FROM wp_bp_groups g, wp_bp_groups_members gm1, wp_bp_groups_groupmeta gm2 WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity'"

I apologize for dumping this on you, and I'm sure you are busy, but this is a feature I would very much like to get working. Any advice or suggestions you could throw my way would be greatly appreciated!

Thanks,
Andrew

@elainevdw
Copy link

This is fantastic! Thanks. Trying to integrate custom group meta was driving me batty, and this helped a lot. The filter_sql() edit in the comments also worked like a charm.

@aaclayton
Copy link

Hmm, clearly this seems to be working for others. I guess I need to take another crack at this. @elainevdw, did you initialize this class in a separate page, or were you able to filter the groups query directly within the groups-loop template?

@aaclayton
Copy link

l got this to work, and it's fantastic! I have three different types of groups on my site, which correspond to different player factions for a video game.
My groups directory: http://tamrielfoundry.com/groups/

I added three new tabs in the directory header in groups/index.php which set the scope for the AJAX query, then I process the querystring in the groups loop to figure out whether to apply a special meta filter. I added this code to the top of my groups/groups-loop.php

// Process the Querystring type
$groupquery = bp_ajax_querystring( 'groups' );
$splitquery = explode( '&' , $groupquery);
$groupsearch = preg_grep( '#scope=#' , $splitquery);
if ( $groupsearch != '' ) {
$groupsearch = explode( '=' , implode( $groupsearch) );
$groupsearch = $groupsearch[1];
}

if ($groupsearch == 'aldmeri' ) :
$meta_filter = new BP_Groups_Meta_Filter( 'group_faction', 'aldmeri' );
elseif ($groupsearch == 'daggerfall' ) :
$meta_filter = new BP_Groups_Meta_Filter( 'group_faction', 'daggerfall' );
elseif ($groupsearch == 'ebonheart' ) :
$meta_filter = new BP_Groups_Meta_Filter( 'group_faction', 'ebonheart' );
endif;

Everything works great, and I'm especially thrilled that it fits seamlessly into the groups directory template and respects additional sub-filtering options. Thanks so much for writing this class Boone.

@aaclayton
Copy link

l got this to work, and it's fantastic! I have three different types of groups on my site, which correspond to different player factions for a video game.
My groups directory: http://tamrielfoundry.com/groups/

I added three new tabs in the directory header in groups/index.php which set the scope for the AJAX query, then I process the querystring in the groups loop to figure out whether to apply a special meta filter. I added this code to the top of my groups/groups-loop.php

// Process the Querystring type
$groupquery = bp_ajax_querystring( 'groups' );
$splitquery = explode( '&' , $groupquery);
$groupsearch = preg_grep( '#scope=#' , $splitquery);
if ( $groupsearch != '' ) {
$groupsearch = explode( '=' , implode( $groupsearch) );
$groupsearch = $groupsearch[1];
}

if ($groupsearch == 'aldmeri' ) :
$meta_filter = new BP_Groups_Meta_Filter( 'group_faction', 'aldmeri' );
elseif ($groupsearch == 'daggerfall' ) :
$meta_filter = new BP_Groups_Meta_Filter( 'group_faction', 'daggerfall' );
elseif ($groupsearch == 'ebonheart' ) :
$meta_filter = new BP_Groups_Meta_Filter( 'group_faction', 'ebonheart' );
endif;

Everything works great, and I'm especially thrilled that it fits seamlessly into the groups directory template and respects additional sub-filtering options. Thanks so much for writing this class Boone.

@sbdm05
Copy link

sbdm05 commented Oct 27, 2014

Hello boonebgorges!
first thank you for posting this!
Unfortunately, iam a real newbie at php/bp, and I dont know how to use your code.
Could you please help me out with this?
I would like each group to select a town, country and activity in the creation process and make this searcheable in the groups directory. To create new fields, i have checked already group extension api and group meta tutorial. (little bit lost if that's the same or not) to create new fields and both worked. but I dont know how to use that metadata to make it' searcheable'. well, thank you a lot in advance!
I hope you can help me with that! Sonia

@sanjaynakate
Copy link

i have tested this code code works good but i am not bale to understand i have select box on group list page like bellow
<select id="groups-order-bydffff"> <option value="user-league">User League</option> <option value="Art and Culture">Art and Culture</option> </select>

if i select Art and Culture i have to show that group which have this meta value so how do send the group name to the loop wanted some thing like this

<?php   if ($groupname=="Art and Culture"){
             $meta_filter = new BP_Groups_Meta_Filter( 'group-custom-field-cat', 'Art and Culture' ); 
               echo @json_decode($meta_filter, true);
}
        ?>  

please any body help me to achieve this using ajax.

@sanjaynakate
Copy link

@aaclayton can you please share the code set the scope for the AJAX query of your tab in header as you have mentioned in the comment on this page.it will help lot of developers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment