public
Last active

Limit a bp_has_groups() loop to groups matching a groupmeta key/value pair

  • Download Gist
gistfile1.aw
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
<?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' ) );
}
}
 
?>

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.

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.

@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;
}

beautiful...works perfect! thanks.

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

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.

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?

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.

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.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.